wxPython Solitaire GUI

时间:2013-11-15 21:57:44

标签: button user-interface wxpython

我正在使用wxPython编写Solitaire GUI,我在Windows 7上编写。我之前只编写过一个GUI(在Java Swing中),所以我并不熟悉因为我可以使用所有不同类型的小部件和控件。我面临着在Solitaire板的Tableaux中拥有可调整大小的级联卡片的挑战。对我来说,每张卡片使用BitmapButtons(或者至少是面朝上的卡片)并且面板包含一堆卡片看起来很自然,因为在Solauire中将Tableau中的一堆卡片从一堆堆放到另一堆堆叠是合法的。我确信有更好的方法可以做到这一点,但是现在我一直在摆弄一个较小的GUI(不是我的主GUI)来尝试实现这一目标。我已经在下面附上了测试GUI的代码。

注意:我的主GUI使用带有14个单元格的GridBagSizer。我还没有尝试过使用GridBagSizer中的以下面板/按钮,甚至不知道GridBagSizer是否是解决此问题的最佳方法。

import wx

class MyFrame(wx.Frame): 
    def __init__(self, parent, id_, title): 
        wx.Frame.__init__(self, parent, id_, title, size=(810, 580))
        self.panel = wx.Panel(self, size=(72, 320), pos=(20,155))
        self.buttons = []
        self.init_buttons()

    def init_buttons(self):
        for i in range(6):
            face_down = wx.Image('img/cardback.png', wx.BITMAP_TYPE_PNG).ConvertToBitmap()
            wid = face_down.GetWidth()
            hgt = face_down.GetHeight()
            bmpbtn = wx.BitmapButton(self.panel, -1, bitmap=face_down, pos=(20,155+7*i), size=(wid, hgt))
            bmpbtn.Bind(wx.EVT_ENTER_WINDOW, self.onMouseOver)
            self.buttons.append(bmpbtn)
        for i in range(1,14):
            rank = 14 - i
            if i % 2 == 0:
                filename = 'img/%sC.png' % rank
            else:
                filename = 'img/%sH.png' % rank
            img = wx.Image(filename, wx.BITMAP_TYPE_PNG).ConvertToBitmap()
            wid = img.GetWidth()
            hgt = img.GetHeight()
            bmpbtn = wx.BitmapButton(self.panel, -1, bitmap=img, pos=(20, 177+20*i), size=(wid, hgt))
            bmpbtn.Bind(wx.EVT_ENTER_WINDOW, self.onMouseOver)
            self.buttons.append(bmpbtn)

    def onMouseOver(self, event):
        #event.Skip()
        pass

class MyApp(wx.App): 
    def OnInit(self): 
        wx.InitAllImageHandlers() 
        self.frame = MyFrame(None, -1, "Solitaire")         
        self.frame.Show(True) 
        self.SetTopWindow(self.frame) 
        return True 

app = MyApp(0) 
app.MainLoop()

这是跑步的结果:

http://oi44.tinypic.com/1zv4swj.jpg

我对此感到满意,直到我将鼠标移到某些按钮上:

http://oi44.tinypic.com/2rdupmq.jpg

这必须与EVT_ENTER_WINDOW事件有关。我试图写一个事件处理程序,但意识到我并不真正知道如何实现我需要的东西。根据文档,BitmapButton的每个状态都有不同的位图 - 悬停,焦点,选定,非活动等。但是,我不想在鼠标悬停事件上更改位图。我只是希望按钮保持不变,而不是在其他按钮上显示。

非常感谢任何帮助。顺便说一句,如果有人建议采用更好的方式(比GridBagSizer和这些按钮面板)来实现这个GUI,我很乐意!

1 个答案:

答案 0 :(得分:0)

我建议不要为每张卡使用实际的窗口控件。相反,我会在一个画布上将卡位图呈现在适当的位置。你需要做一些额外的数学运算来确定点击哪些卡片,但这绝对是你要走的路。

使用wx.PanelEVT_PAINT处理程序进行绘图。

这是一个使用双缓冲来避免闪烁的起点。

P.S。您可以使用bitmap = wx.Bitmap(path)加载图片,而不是费心wx.Image并将其转换为位图对象。

import wx

class Panel(wx.Panel):
    def __init__(self, parent):
        super(Panel, self).__init__(parent)
        self.SetBackgroundStyle(wx.BG_STYLE_CUSTOM)
        self.Bind(wx.EVT_PAINT, self.on_paint)
        self.Bind(wx.EVT_LEFT_DOWN, self.on_left_down)
        self.Bind(wx.EVT_LEFT_UP, self.on_left_up)
    def on_left_down(self, event):
        print 'on_left_down', event.GetPosition()
    def on_left_up(self, event):
        print 'on_left_up', event.GetPosition()
    def on_paint(self, event):
        dc = wx.AutoBufferedPaintDC(self)
        # Use dc.DrawBitmap(bitmap, x, y) to draw the cards here

class Frame(wx.Frame):
    def __init__(self):
        super(Frame, self).__init__(None)
        self.SetTitle('My Title')
        Panel(self)

def main():
    app = wx.App()
    frame = Frame()
    frame.Center()
    frame.Show()
    app.MainLoop()

if __name__ == '__main__':
    main()