在wxPython中,如何获取ScrolledPanel中与图片相关的鼠标位置?

In wxPython, how to get the mouse position related to image in ScrolledPanel?

我正在使用 wxPython 实现一个简单的地图编辑器。 ScrolledPanel 中托管了一个 StaticBitmap 图像控件。图像尺寸大于面板尺寸,因此出现滚动条。在鼠标移动事件处理程序中,函数 event.GetPosition() 能够获取与 面板 左上角相关的鼠标位置.但是,我想获取与 image 左上角相关的鼠标位置。我怎样才能做到这一点?谢谢

例如第一个截图(滚动到顶部),如果鼠标在面板的左上角,图像相关的位置应该是(0, 0)。在第二个屏幕截图中(滚动到底部),如果鼠标在面板的左上角,则与图像相关的位置是 (0, image_height-panel_height).

#!/usr/bin/python

import wx
import wx.lib.scrolledpanel

class SimpleFrame(wx.Frame):
    def __init__(self, parent):
        super(SimpleFrame, self).__init__(parent)

        # add a panel so it looks the correct on all platforms
        self.frame_panel = wx.Panel(self)
        frame_panel = self.frame_panel
        # image panel
        self.image_panel = wx.lib.scrolledpanel.ScrolledPanel(frame_panel, style=wx.SIMPLE_BORDER)
        image_panel = self.image_panel
        image_panel.SetAutoLayout(True)
        image_panel.SetupScrolling()
        # image panel - image control
        self.image_ctrl = wx.StaticBitmap(image_panel)
        self.image_ctrl.Bind(wx.EVT_MOTION, self.ImageCtrl_OnMouseMove)
        img = wx.Image("image.jpg", wx.BITMAP_TYPE_ANY)
        self.image_ctrl.SetBitmap(wx.BitmapFromImage(img))
        image_panel.Layout()
        image_sizer = wx.BoxSizer(wx.VERTICAL)
        image_sizer.Add(self.image_ctrl)
        image_panel.SetSizer(image_sizer)
        # frame sizer
        frame_sizer = wx.BoxSizer(wx.HORIZONTAL)
        frame_sizer.Add(image_panel, proportion=1, flag=wx.EXPAND | wx.ALL)
        frame_panel.SetSizer(frame_sizer)
        return

    def ImageCtrl_OnMouseMove(self, event):
        # position in control
        ctrl_pos = event.GetPosition()
        print("ctrl_pos: " + str(ctrl_pos.x) + ", " + str(ctrl_pos.y))
        # position in image
        #image_pos = ??? convert control position to image position
        #print("image_pos: " + str(image_pos.x) + ", " + str(image_pos.y))


app = wx.PySimpleApp()
frame = SimpleFrame(None)
frame.Show()
app.MainLoop()

滚动到顶部:

滚动到底部:

您需要使用GetScreenPosition()获取window当前位置的坐标,使用ScreenToClient()获取图像的客户端坐标。把它们加在一起,你就会得到你在图像上的相对位置。
这样做的好处在于,用户可以重新定位 window 或更改其大小,从而获得一致的位置。

这是您修改后的代码:

#!/usr/bin/python

import wx
import wx.lib.scrolledpanel

class SimpleFrame(wx.Frame):
    def __init__(self, parent):
        super(SimpleFrame, self).__init__(parent)

        # add a panel so it looks the correct on all platforms
        self.frame_panel = wx.Panel(self)
        frame_panel = self.frame_panel
        # image panel
        self.image_panel = wx.lib.scrolledpanel.ScrolledPanel(frame_panel, style=wx.SIMPLE_BORDER)
        image_panel = self.image_panel
        image_panel.SetAutoLayout(True)
        image_panel.SetupScrolling()
        # image panel - image control
        self.image_ctrl = wx.StaticBitmap(image_panel)
        self.image_ctrl.Bind(wx.EVT_MOTION, self.ImageCtrl_OnMouseMove)
        self.img = wx.Image("image.jpg", wx.BITMAP_TYPE_ANY)
        self.image_ctrl.SetBitmap(wx.BitmapFromImage(self.img))
        image_panel.Layout()
        image_sizer = wx.BoxSizer(wx.VERTICAL)
        image_sizer.Add(self.image_ctrl)
        image_panel.SetSizer(image_sizer)
        # frame sizer
        frame_sizer = wx.BoxSizer(wx.HORIZONTAL)
        frame_sizer.Add(image_panel, proportion=1, flag=wx.EXPAND | wx.ALL)
        frame_panel.SetSizer(frame_sizer)
        return

    def ImageCtrl_OnMouseMove(self, event):
        # position in control
        ctrl_pos = event.GetPosition()
        print("ctrl_pos: " + str(ctrl_pos.x) + ", " + str(ctrl_pos.y))
        pos = self.image_ctrl.ScreenToClient(ctrl_pos)
        print "pos relative to screen top left = ", pos
        screen_pos = self.frame_panel.GetScreenPosition()
        relative_pos_x = pos[0] + screen_pos[0]
        relative_pos_y = pos[1] + screen_pos[1]
        print "pos relative to image top left = ", relative_pos_x, relative_pos_y


app = wx.PySimpleApp()
frame = SimpleFrame(None)
frame.Show()
app.MainLoop()

我知道这是一个旧话题,但对于所有登陆这里的人(像我一样),还有另一种方式:

def OnMouseMove(self, event):
    dc = wx.ClientDC(self)
    self.DoPrepareDC(dc)
    pos = event.GetLogicalPosition(dc)