python - wxPython:在面板上拖放 wx.Button 会使应用程序崩溃
问题描述
我正在尝试构建一个用户可以在面板周围拖放一些按钮的应用程序。我首先有一个关于鼠标捕获事件丢失的错误,我最终发现我必须捕获这个事件以防止错误。
但是现在,当我运行应用程序时,我可以拖放按钮,但是在释放鼠标左键后应用程序完全冻结。
我必须从终端使用 Ctrl+C 停止它,否则我的鼠标在桌面环境中的任何其他窗口中都无法使用。
我怀疑鼠标捕获事件的问题没有得到很好的处理。
我正在使用从包(apt)安装的 Python 3.5 在 Ubuntu 16.04 下工作。我尝试使用从包(apt)安装的 wxPython 4.0.0 以及从 pip 安装的最新 wxPython 4.0.4。
在这两种情况下,应用程序在单击或拖放按钮后完全冻结。
import wx
class DragButton(wx.Button):
def __init__(self, parent, id=wx.ID_ANY, label="", pos=(0, 0)):
super().__init__(parent=parent, id=id, label=label, pos=pos)
self._dragging = False
self.Bind(wx.EVT_LEFT_DOWN, self.OnLeftDown)
self.Bind(wx.EVT_LEFT_UP, self.OnLeftUp)
self.Bind(wx.EVT_MOTION, self.OnMouseMove)
self.Bind(wx.EVT_MOUSE_CAPTURE_LOST, lambda evt: None)
def OnLeftDown(self, evt):
print("Left down")
if not self.HasCapture():
self.CaptureMouse()
x, y = self.ClientToScreen(evt.GetPosition())
originx, originy = self.GetPosition()
dx = x - originx
dy = y - originy
self.delta = ((dx, dy))
def OnLeftUp(self, evt):
print("Left UPPPP")
if self.HasCapture():
self.ReleaseMouse()
def OnMouseMove(self, evt):
if evt.Dragging() and evt.LeftIsDown():
x, y = self.ClientToScreen(evt.GetPosition())
fp = (x - self.delta[0], y - self.delta[1])
self.Move(fp)
class GDomFrame(wx.Frame):
def __init__(self, parent, title):
super().__init__(parent, title=title, size=(350, 300))
self._init_ui()
self.Centre()
def _init_ui(self):
panel = wx.Panel(self)
self.button = DragButton(panel, label="Drag me", pos=(10, 10))
if __name__ == '__main__':
print("wxPython version: {}".format(wx.__version__))
app = wx.App()
ex = GDomFrame(None, title='GDom Application')
ex.Show()
app.MainLoop()
使用此代码,我希望有一个可以在面板上多次移动的按钮。
解决方案
我测试了一个类似的脚本。它在 Windows 上运行良好,但在 ubuntu 16.04 上运行良好。我解决了这样的问题。
def OnLeftDown(self, evt):
print("Left down")
if not self.HasCapture():
self.CaptureMouse()
self.ReleaseMouse() # <------
我的脚本:
import wx
class Mywin(wx.Frame):
def __init__(self, parent, title):
super(Mywin, self).__init__(parent, title = title,size = (400,200))
self.InitUI()
self.Centre()
def InitUI(self):
self.panel = wx.Panel(self)
vbox = wx.BoxSizer(wx.VERTICAL)
self.btn = wx.Button(self.panel,-1,"click Me",pos=(10, 10))
vbox.Add(self.btn,0,wx.ALIGN_CENTER)
self.btn.Bind(wx.EVT_LEFT_DOWN, self.OnMouseDown)
self.btn.Bind(wx.EVT_MOTION, self.OnMouseMove)
self.btn.Bind(wx.EVT_LEFT_UP, self.OnMouseUp)
print ("Init pos:",self.btn.GetPosition())
def OnMouseDown(self, event):
if (not self.btn.HasCapture()):
self.btn.CaptureMouse()
self.btn.ReleaseMouse()
sx,sy = self.panel.ScreenToClient(self.btn.GetPosition())
dx,dy = self.panel.ScreenToClient(wx.GetMousePosition())
self.btn._x,self.btn._y = (sx-dx, sy-dy)
def OnMouseMove(self, event):
if event.Dragging() and event.LeftIsDown():
x, y = wx.GetMousePosition()
self.btn.SetPosition(wx.Point(x+self.btn._x,y+self.btn._y))
print(self.btn.GetPosition())
def OnMouseUp(self, event):
if (self.btn.HasCapture()):
self.btn.ReleaseMouse()
print ("Final pos:",self.btn.GetPosition())
def main():
app = wx.App()
w = Mywin(None, title='Button demo')
w.Show()
app.MainLoop()
if __name__ == '__main__':
main()
推荐阅读
- networking - 检查端口 53 上的机器可达性
- arrays - 使用年份存档的所有链接创建一个数组(自定义帖子类型)
- python - 如何使用python map函数在Qtablewidget中设置项目
- node.js - 在 API 请求仍在运行时从 lambda 函数提前返回是否存在风险?
- javascript - 如何刷新 github 个人访问令牌
- apache-spark-sql - Spark SQL从字符串字段返回数据保存json字典样式
- amazon-web-services - 如何销售自定义 AWS AMI
- c# - 无法将工作服务作为 Windows 服务启动
- c# - 从与 AsyncCrudAppService 的关系中获取数据
- sapui5 - SAP Web IDE 警告:“未定义控件 ID。请输入唯一 ID。”