2013-11-15 32 views
1

我正在使用wxPython编写Solitaire GUI,而且我在Windows 7上。我只写了一个GUI(在Java Swing中),所以我不像我一样熟悉所有不同类型的小部件和控件。我面临的挑战是在纸牌板的桌面上有可调整大小的层叠卡片。对我来说,对每张卡片(或至少对于正面向上的卡片)使用BitmapButtons并使面板包含一堆卡片似乎很自然,因为将Tableau中的子卡片从堆叠移动到纸牌是合法的。我确信有更好的方法来做到这一点,但现在我一直在摆弄一个更小的GUI(不是我的主GUI)来尝试实现这一点。我附上了下面测试GUI的代码。wxPython Solitaire 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的建议,我会喜欢!

回答

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() 
+0

感谢您的出发点代码和快速响应。我希望不必做额外的数学运算,因为面朝下的卡片比面朝上的卡片更密集。还有用户调整窗口大小的问题,那么我的鼠标位置会发生什么? 为什么你建议不要使用按钮,以及如何从使用单个画布中受益? 谢谢! – Liz

+0

只要你想做任何不是简单的位图按钮的图形,你都会被卡住。这就是为什么。按照我的建议来做并不难。你可以绑定到'EVT_SIZE'并重绘(self.Refresh())。您可以在绘制过程中考虑窗口大小以便正确绘制 – FogleBird

+0

我一直在仔细研究代码,并提出了一个非常好的GUI。我没有使用一个面板,而是为所有十三个面板制作了面板,这样我就可以很容易地找出哪个卡片是用面板的位置作为偏移来点击的。 :) http://oi42.tinypic.com/348povc.jpg 我不确定为什么有些图片不能正确显示(例如,废物(第二顶部)中的面朝下图像),但它必须是一个不同的错误。 非常感谢您的帮助:) – Liz