Подвижный объект wxPython на странице с изменяемым размером

#python #user-interface #wxpython

#python #пользовательский интерфейс #wxpython

Вопрос:

Я пытаюсь написать простое приложение, которое позволит перемещать кнопки, я использовал пример, который я нашел здесь, в Stack overflow — извините, я не могу найти исходную ссылку: (

Кнопки перемещаются, как и ожидалось, но как только изменяется размер рамки, позиции кнопок возвращаются в исходное положение, и я не понимаю, поскольку я устанавливаю положение и не уверен, что их сбрасывает и почему.

Код:

 import wx

app = wx.App(False)
d = {}

def MouseDown(e):
    print('mouse down')
    o           = e.GetEventObject()
    sx,sy       = panel.ScreenToClient(o.GetPositionTuple())
    dx,dy       = panel.ScreenToClient(wx.GetMousePosition())
    o._x,o._y   = (sx-dx, sy-dy)
    d['d'] = o
    print(o)

def MouseMove(e):
    try:
        if 'd' in d:
            print("mouse move has been triggered")

            o = d['d']
            x, y = wx.GetMousePosition()
            o.SetPosition(wx.Point(x o._x,y o._y))
    except:
        print('fail')
        pass

def MouseUp(e):
    try:
        if 'd' in d: del d['d']
    except: pass

frame = wx.Frame(None, -1, 'simple.py')
panel = wx.Panel(frame)
box = wx.BoxSizer(wx.VERTICAL)
button1 = wx.Button(panel, -1, "foo")
box.Add(button1, 0, wx.ALL, 10)
button2 = wx.Button(panel, -1, "bar")
box.Add(button2, 0, wx.ALL, 10)

button1.Bind(wx.EVT_LEFT_DOWN, MouseDown)
button2.Bind(wx.EVT_LEFT_DOWN, MouseDown)

button1.Bind(wx.EVT_MOTION, MouseMove)
button2.Bind(wx.EVT_MOTION, MouseMove)

button1.Bind(wx.EVT_LEFT_UP, MouseUp)
button2.Bind(wx.EVT_LEFT_UP, MouseUp)

panel.Bind(wx.EVT_MOTION, MouseMove)
panel.Bind(wx.EVT_LEFT_UP, MouseUp)

panel.SetSizer(box)
panel.Layout()
frame.Show()

app.MainLoop()
  

Ответ №1:

Это Sizer перемещение кнопок при изменении размера фрейма.
т. Е. Выполнение своей работы

Разработчик отвечает за размещение его содержимого.
Вы перемещаете элементы вручную, но как только размер рамки изменяется, активируются sizer / s и возвращают работоспособность в макет. Непреднамеренно для вас, отменяя то, что вы хотели, чтобы произошло.
Если вам нужна эта функциональность, которая в реальном приложении привела бы к хаосу (без каламбура), используйте ручное позиционирование и избегайте размеров.

Комментарии:

1. Спасибо за объяснение. Может ли у вас быть ручное позиционирование внутри элемента sizer?

2. @LittleMissChaos Короче говоря, нет. Не так, как вы предлагаете выше в своем коде. С помощью некоторого сложного кодирования вы можете изменить относительные позиции, особенно с помощью a GridBagSizer , но, по сути, позиция будет определяться sizer, в зависимости от того, как вы заполнили sizer. Если вы думаете об этом как о команде с определенными позициями игроков, они не могут бесконечно меняться местами во время игры. По сути, разработчик является арбитром, устанавливающим правила. Вы, конечно, можете выбрать бесплатную игру без рефери ( sizer ).