Подходящие wx.Sizer(s) для работы?

У меня есть пространство, в котором я хотел бы, чтобы определенные элементы (представленные здесь A, B, D и G) находились в своем собственном «углу» дизайна. Углы должны выстроиться так, как будто каждый из четырех элементов отталкивает другой; Прямоугольник. Это должно содержаться в неизменяемой панели. У меня будет несколько одинаковых панелей, и я хочу сохранить максимально идентичное расположение элементов. (Мне нужно было что-то более сложное, чем wx.Wizard, но с той же общей идеей.)

AAAAAAAAAA      BB


CCCCCCCCCCCCCCCCCC
CCCCCCCCCCCCCCCCCC
CCCCCCCCCCCCCCCC
CCCCCCCCCCCCCC
CCCCCCCCCCCCCCCCCC
CCCCCCCCCCCCCCCC
CCCCCCCCCCCCCCCCCC


DDD EEE FFF    GGG

A представляет текст крупным шрифтом.

B представляет собой числовой индикатор выполнения (например, «1 из 7») мелким шрифтом.

C представляет большой блок текста.

D, E, F и G — кнопки.

Кнопка G отделена от других для функциональности.

Я безуспешно пытался вложить wx.BoxSizers (горизонтальные блоки внутри одного вертикального блока). Моя первая проблема с wx.BoxSizer заключается в том, что .SetMinSize в моей последней строке не соблюдается. Вторая проблема заключается в том, что я понятия не имею, как заставить кнопку G «занимать место», не становясь при этом комично большой, или как я могу прижать ее к правому краю и нижнему краю.

Я пытался использовать wx.GridBagSizer, но столкнулся с совершенно другими проблемами.

После изучения различных онлайн-руководств и wxPython в действии я немного расстроен. Соответствующие форумы проявляют активность раз в две недели. «Поиграться с этим» ни к чему меня не привело; Мне кажется, что я пытаюсь разгладить бугорок в плохо уложенном ковре.


person MetaHyperBolic    schedule 30.03.2010    source источник


Ответы (3)


Используя BoxSizers и некоторые флаги, такие как wx.EXPAND и wx.ALIGN_RIGHT и т. д., вы можете получить то, что хотите. Вот пример

import wx
import string
AF = string.ascii_uppercase[:7]

class MyFrame(wx.Frame):

    def __init__(self):
        wx.Frame.__init__(self, None, size=(300,300))

        a, b, c, d, e, f, g = [wx.Button(self, -1, 4*c) for c in AF]
        a.SetMaxSize((200,100))   # 'a' won't get bigger than 200 wide

        # build the top row (with sizers I usually work from inside to out)
        hs0 = wx.BoxSizer(wx.HORIZONTAL)
        hs0.Add(a, 1, wx.ALIGN_LEFT)  # 1 here means expand with weight 1
        hs0.Add((0,0), 1)  # also expand the spacing
        hs0.Add(b, 0, wx.ALIGN_RIGHT)  # 0 means don't expand this

        # build the bottom row
        hs1 = wx.BoxSizer(wx.HORIZONTAL)
        hs1.Add(d, 0, wx.ALIGN_LEFT)
        hs1.Add((10,10), 0)
        hs1.Add(e, 0)
        hs1.Add((10,10), 0)
        hs1.Add(f, 0)
        hs1.Add((10, 10), 1)
        hs1.Add(g, 0, wx.ALIGN_RIGHT)

        # stack the rows vertically
        vs = wx.BoxSizer(wx.VERTICAL)
        vs.Add(hs0, flag=wx.EXPAND)   # expand in the orthogonal direction to sizer (here horizontal)
        vs.Add(c, 1, flag=wx.EXPAND)  
        vs.Add(hs1, flag=wx.EXPAND)
        self.SetSizer(vs)

app = wx.PySimpleApp()
frame = MyFrame()
frame.Show(1)
app.MainLoop()

альтернативный текст

person tom10    schedule 31.03.2010
comment
Я поставил ответ ниже с кодом и изображением. Или хотя бы ссылку на малюсенькую картинку. Никак не получается связать изображения. - person MetaHyperBolic; 31.03.2010
comment
Да, конечно, я займусь изучением. Даже без благодарности или одобрения или какого-либо объяснения того, почему мой ответ не работает для вас (хотя я вижу, что вы вставили мой код без указания авторства в своем ответе), или даже без того, чтобы вы потратили время, чтобы выяснить, как загрузить фото, мне не терпится провести остаток дня, помогая вам решить вашу проблему... - person tom10; 31.03.2010
comment
Косметически? Выглядит отлично. Но ваш код вернул ту же проблему, что и у меня при переключении между панелями. В первый раз выглядит нормально, но как только я переключаюсь между панелями, макет решает, что он должен отличаться от фрейма. Немного преждевременно голосовать, когда я еще не знаю, что на самом деле решает проблему. - person MetaHyperBolic; 01.04.2010

Во-первых, вам нужен вертикальный размер, чтобы разделить окно на 3 строки: AB, C и DEFG:

frame_sizer = wx.BoxSizer(wx.VERTICAL)

Далее вам понадобится горизонтальный размер для первого ряда:

first_sizer = wx.BoxSizer(wx.HORIZONTAL)
# add the items A and B to first_sizer
# now we add first_sizer to frame_sizer
frame_sizer.Add(first_sizer)

Затем для второй строки мы просто добавляем элемент управления C к размернику:

frame_sizer.Add(C)

... убедившись в следующем:

  • Элемент управления создается с заданным размером (через его конструктор)
  • Элементу управления присваивается минимальный размер (C.SetMinSize())

Теперь, для последнего ряда, вероятно, лучше всего использовать другой горизонтальный размер.

wx.BoxSizer(wx.HORIZONTAL)
# add DEF
# now add some space between them
wx.AddSizer(10)
# now add G

Надеюсь, это сработает для вас. Если нет, лучше всего использовать дизайнер графического интерфейса, такой как wxSmith в Code::Blocks (который разработан для C++, но может использоваться, по крайней мере, чтобы получить представление о том, как все будет выглядеть — предполагается, что wxPython имеет 1-к -1 переписка с wxWidgets)

person Nathan Osman    schedule 30.03.2010
comment
Это была моя предыдущая стратегия, которая потерпела неудачу. Каждая строка сайзера должна иметь другую ширину, чем другие строки. Я не вижу способа сказать: Эй, там! Вы должны быть x пикселей в ширину, не больше, не меньше. Ты сюда! Вы получаете то же самое. Не похоже, чтобы Code::Blocks работал в Windows 7. По сравнению с этим мой опыт разработки кроссбраузерных сайтов на заре CSS кажется тривиальным. - person MetaHyperBolic; 30.03.2010
comment
Ах, да. Я забыл - вы должны вызывать Add с флагом wx.EXPAND, когда добавляете сайзеры. Это должно делать свое дело. - person Nathan Osman; 31.03.2010
comment
@MetaHyperBolic: Code::Blocks должен нормально работать в Windows 7. - person Nathan Osman; 31.03.2010
comment
codeblocks.org/downloads/5 даже не указывает Windows 7 в качестве опции. На этой странице предполагается, что компилятор, поставляемый с Code::Blocks, не будет работать в Vista. И я, очевидно, должен скомпилировать wxWidgets для использования wxSmith, поэтому мне пришлось перейти на Windows XP. - person MetaHyperBolic; 31.03.2010
comment
@MetaHyperBolic: я использую его в Vista без проблем (и я активно использовал его больше года). Он должен нормально работать с Windows 7. Вам НЕ нужно компилировать wxWidgets для использования wxSmith. Он поставляется с предварительно настроенным Code::Blocks. Совет из моего первого комментария сработал? - person Nathan Osman; 31.03.2010
comment
Нет, wx.EXPAND — это одна из первых вещей, к которой я потянулся. Расширения не произошло. Что ж, в результате поиска сообщений об ошибках, которые я получил при попытке запустить wxSmith без компиляции wxWidgets, я попал на страницу на их форумах, где разработчики в какой-то момент предложили посетить эту страницу, которая была о том, как вы необходимо скомпилировать wxWidgets. Поиски заняли пару часов, но, наконец, я запустил wxSmith. Я не очень понимаю, как это работает, несмотря на учебник. - person MetaHyperBolic; 31.03.2010
comment
Хммм... Я думал, что это точно исправит. Каждый из элементов управления в сайзерах установлен на wx.EXPAND? Для wxSmith попробуйте щелкнуть вкладку Layout и добавить сайзеры. Затем попробуйте добавить элементы управления к сайзерам и посмотреть, как они работают. Если вы поиграетесь с настройками на панели Properties, вы можете найти что-то, что работает. С надеждой... :) - person Nathan Osman; 31.03.2010
comment
Я добавил урезанный список кода, показывающий мои попытки с кодом tom10. - person MetaHyperBolic; 31.03.2010

У меня есть только один кадр. У меня есть несколько панелей, встроенных в раму. Все они скрыты, кроме одного. Кнопка «Далее» выполняет .Hide() на этой панели, а затем вызывает функцию с именем .ShowYourself. Я хотел что-то похожее на Wizard, что вы можете увидеть в предыдущий вопрос

Я пытаюсь поставить сайзер на панель. Как видно из http://tinypic.com/r/14nh651/5 , я не могу заставить размерчик занимать всю панель. Изображение не отображается при предварительном просмотре, поэтому оно находится по адресу http://tinypic.com/r/14nh651/5.

import wx
import sys

class MyApp(
    wx.App      # This makes a subclass of the wx.App class

):

def OnInit(self):
    # image = wx.Image('wxPython.jpg', wx.BITMAP_TYPE_JPEG)
    self.frame = MyFrame(None)
    self.frame.Show()
    self.SetTopWindow(self.frame)
    return True

def OnExit(self):
    print 'Dying ...'

####################################################################################################

class MyFrame(
    wx.Frame    # This makes a subclass of the wx.Frame class
    ):
    """Frame class that displays an image."""

    def __init__(self, 
        image, 
        parent=None,                # "None" as a parameter means this is a top-level window
        id=-1,                  # "-1" means automatically generate a new ID
        title='Generic Title',          # What words appear in the title bar?
        pos=wx.DefaultPosition,         # Where is the upper left-hand corner?
        style=wx.CAPTION | wx.STAY_ON_TOP   # Style with only a caption
        ):      

    """Create a wx.Frame instance and display image."""

    size = (500, 500)
    wx.Frame.__init__(self, parent, id, 'Program Title', pos, size, style)

    sizer_h = wx.BoxSizer(wx.HORIZONTAL)

    self.panelX = TestLayout3(self)     
    sizer_h.Add(self.panelX)

    self.SetSizer(sizer_h)

    self.panelX.ShowYourself()

def ShutDown(self):

        self.Destroy()

####################################################################################################

class TestLayout3(wx.Panel):

# 0 - Splash screen with "Next" and "Cancel and Exit" buttons

def __init__(self, parent, id=-1):
    size = (600, 600)
    wx.Panel.__init__(self, parent, id, size)

    a, b, c, d, e, f, g = [wx.Button(self, -1, 4*c) for c in 'ABCDEFG']
    a.SetMaxSize((200,100))   # 'a' won't get bigger than 200 wide

    # build the top row (with sizers I usually work from inside to out)
    hs0 = wx.BoxSizer(wx.HORIZONTAL)
    hs0.Add(a, 1, wx.ALIGN_LEFT)  # 1 here means expand with weight 1
    hs0.Add((0,0), 1)  # also expand the spacing
    hs0.Add(b, 0, wx.ALIGN_RIGHT)  # 0 means don't expand this

    # build the bottom row
    hs2 = wx.BoxSizer(wx.HORIZONTAL)
    hs2.Add(d, 0, wx.ALIGN_LEFT)
    hs2.Add((10,10), 0)
    hs2.Add(e, 0)
    hs2.Add((10,10), 0)
    hs2.Add(f, 0)
    hs2.Add((10, 10), 1)
    hs2.Add(g, 0, wx.ALIGN_RIGHT)

    # stack the rows vertically
    vs = wx.BoxSizer(wx.VERTICAL)
    vs.Add(hs0, flag=wx.EXPAND)   # expand in the orthogonal direction to sizer (here horizontal)
    vs.Add(c, 1, flag=wx.EXPAND)  
    vs.Add(hs2, flag=wx.EXPAND)
    self.SetSizer(vs)

    self.Raise()
    self.SetPosition((0,0))
    self.Fit()  
    self.Hide()


# reveal this panel
def ShowYourself(self):
    self.Raise()
    self.SetPosition((0,0))
    self.Fit()
    self.Show()


# what do we do when the "Back" button is clicked?
def OnBack(self, event):
    self.Hide()
    self.GetParent().panel1.ShowYourself()

# what do we do when the "Next" button is clicked?
def OnNext(self, event):
    self.Hide()
    self.GetParent().panel1.ShowYourself()

    ![# what do we do when the "Cancel and Exit" button is clicked?
    def OnCancelAndExit(self, event):
        self.GetParent().ShutDown()

####################################################################################################

def main():
    app = MyApp(redirect = False)
    app.MainLoop()

####################################################################################################

if __name__ == '__main__':
    main()][3]
person MetaHyperBolic    schedule 31.03.2010
comment
@MetaHyperBolic: Во-первых, когда вы добавляете панель в сайзер, вы не используете флаг wx.EXPAND. Кроме того, вы можете попробовать вызвать sizer_h.SetSizeHints(self) после вызова SetSizer. Попробуйте это и посмотрите, работает ли это. Что касается ссылки на изображение в вашем посте, вы добавили его как: <img src="http...">? - person Nathan Osman; 31.03.2010
comment
Верно. Я пытался добавить панель в сайзер с помощью wx.EXPAND раньше (вы видите очень урезанный скрипт, с закомментированными предыдущими проблемами) - в итоге я столкнулся со всеми видами странных проблем, потому что у меня было семь панелей, добавленных к размеру. сайзер на фрейме верхнего уровня. - person MetaHyperBolic; 31.03.2010
comment
Я просто щелкнул значок изображения на панели инструментов и сделал это вместо того, чтобы пытаться добавить HTML, с которым я более знаком. - person MetaHyperBolic; 31.03.2010
comment
Дайте мне немного времени, и я попробую ваш сценарий. Может быть, тогда я смогу найти проблему - это действительно меня сбило с толку. - person Nathan Osman; 31.03.2010
comment
Я смог воспроизвести проблему. Сейчас попробую найти решение. - person Nathan Osman; 31.03.2010
comment
Все, что я сделал, это изменил sizer_h.Add(self.panelX) на sizer_h.Add(self.panelX,1,wx.EXPAND), и теперь панель занимает все окно. Разве это не то, чего ты хочешь? - person Nathan Osman; 31.03.2010
comment
Я попробовал это, и теперь это работает с моей версией Very Very Very Stripped Down. Я думаю, часть проблемы в том, что это мой первый проект с wxPython, и он относительно сложный. Я даже не в пределах компетенции крика и, вероятно, представил множество тонких вопросов. - person MetaHyperBolic; 01.04.2010
comment
Продолжайте пытаться. Ты хорошо справляешься. Мне потребовалось некоторое время, прежде чем я понял, как работают сайзеры. - person Nathan Osman; 01.04.2010