이번 강의는 저번 강의에 이어서 레이아웃 기능 중 하나인 GridSizer, FlexGridSizer, GridBagSizer를 알아보겠습니다.
1. GridSizer
Grid는 일반적으로 이차원의 직선이나 곡선으로 이루어진 격자를 뜻합니다.
(0, 0) | (1, 0) | (2, 0) | (3, 0) |
(0, 1) | (1, 1) | (2, 1) | (3, 1) |
(0, 2) | (1, 2) | (2, 2) | (3, 2) |
(0., 3 | (1, 3) | (2, 3) | (3, 3) |
(0, 4) | (1, 4) | (2, 4) | (3, 4) |
위와 같은 직선으로 이루어진 격자 공간에 위젯을 배치하는 것을 GridSizer라고 합니다. 위의 경우에는 5 x 4의 GridSizer라고 할 수 있습니다.
GridSizer도 이전 시간의 BoxSizer와 비슷하게 이루어집니다.
button_sizer = wx.GridSizer(5, 4, 0, 0)
GridSizer의 각각의 파라미터는 다음을 뜻합니다.
- rows : 행의 갯수
- cols : 열의 개수
- vgap : 가로 단위의 공간. 이 수치만큼 각각의 위젯들은 가로로 벌어집니다.
- hgap : 세로 단위의 공간. 이 수치만큼 각각의 위젯들은 세로로 벌어집니다.
저는 5 x 4의 GridSizer를 선언해 보았습니다.
sizer.Add(button_sizer, 1, wx.EXPAND, 5)
이것을 원래의 BoxSizer의 밑에 추가하면 BoxSizer에 포함된 위젯의 밑에 GridSizer에 포함된 위젯들이 선언된 행렬의 크기로 들어갑니다.
BoxSizer의 위젯들 | |||
GridSizer의 위젯들 | |||
순서를 바꾸고 싶다면 Add의 순서를 GridSizer부터 선언하시면 됩니다.
sizer.Add(button_sizer, 1, wx.EXPAND, 5)
sizer.Add(self.button, 0, wx.ALL, 5)
sizer.Add(self.button2, 0, wx.ALL, 5)
위와 같이 선언하면 GridSizer의 위젯이 먼저 들어가고, 그 밑에 BoxSizer의 위젯들이 들어가게 됩니다.
이제 GridSizer에 버튼들을 추가해보겠습니다. 이때 버튼을 하나하나 선언하여 추가하기엔 비효율적이므로 for문을 통해서 추가하겠습니다.
for i in range(20):
button = wx.Button(self, label='버튼')
button_sizer.Add(button)
이렇게 하면 20개의 버튼이 GridSizer에 추가되게 됩니다.
이제 결과를 보겠습니다.
총 20개의 버튼이 GridSizer에 추가되었음을 확인할 수 있습니다.
2. FlexGridSizer
FlexGridSizer는 일반적인 GridSizer와 비슷합니다. 하지만 Flex라는 이름에서 알 수 있듯이 유연한 GridSizer입니다. FlexGridSizer의 위젯들은 화면의 크기에 따라서 위치를 바꿀 수 있습니다.
button_sizer = wx.FlexGridSizer(5, 4, 0, 0)
FlexGridSizer는 일반적인 GridSizer의 선언 방식과 완전히 똑같습니다. 하지만 위의 코드에서 GridSizer를 FlexGridSizer로 바꾸기만 해서는 어느 부분이 Flex인지 알기 힘듭니다.
그 이유는 FlexGridSizer에는 추가적으로 몇 개의 행과 열이 Flex 할지 정해주는 코드가 필요하기 때문입니다.
button_sizer.AddGrowableCol(1)
button_sizer.AddGrowableRow(1)
위의 코드를 통해 행과 열에 1줄씩 Flex 하도록 만들었습니다. 이제 결과를 확인해보겠습니다.
버튼 위젯들이 화면 크기에 따라서 위치가 바뀌는 것을 볼 수 있습니다.
3. GridBagSizer
GridBagSizer는 앞의 GridSizer의 진화형입니다. GridSizer가 단순히 추가된 순서대로 위젯을 정해진 위치에 넣었다면, GridBagSizer는 가방을 싸듯이(Bag) 원하는 위치에 넣을 수 있습니다. 또한 가방의 주머니처럼 위젯이 차지하는 공간 또한 원하는 대로 바꿔줄 수 있습니다.
button_sizer = wx.GridBagSizer(5, 4)
GridBagSizer는 다른 GridSizer와 다르게 행렬의 크기만 파라미터로 받습니다. 그 이유는 위젯을 Add 할 때 나타납니다.
button_sizer.Add(button, (i * 2, i * 2), (2, 2), wx.EXPAND)
GridBagSizer는 위젯을 Add할 때에 추가적인 인수를 받습니다.
- window : 어느 위젯을 포함시킬지
- pos : 어느 위치에 위젯을 넣을지
- sapn : 위젯이 차지하는 크기는 얼마인지
- flag : 어떠한 방식으로 위젯을 넣을지
저는 위의 for문을 그대로 가져가기에 각각의 위젯들은 (2, 2)의 공간을 가지며, 그 공간에서 최대의 크기를 가지고(wx.EXPAND), for문의 인수 i의 두배에 해당하는 (x, y) 좌표에 위치(i * 2, i * 2)시키도록 합니다.
결과 이미지를 보시면 각각의 위젯들은 좌표를 가지며, 원래의 버튼 크기(버튼 2)보다 세로 길이가 살짝 더 큰 것을 볼 수 있습니다.
또한 GridBagSizer를 선언할 때 정했던 범위를 벗어나는 것을 볼 수 있습니다. 이것이 다른 GridSizer들에는 없는 GridBagSizer만의 특징입니다.
4. 마치며
이번 시간에는 GridSizer의 3가지 종류에 대해서 알아보았습니다. 다음 시간에는 문자를 표현할 수 있는 StaticText와 TextCtrl에 대해서 알아보겠습니다.
import wx
class Mainframe(wx.Frame): # GridSizer 기준 코드
def __init__(self, parent, id, title):
wx.Frame.__init__(self, parent, id, title, size=(500, 500))
# sizer = wx.BoxSizer(wx.VERTICAL)
sizer = wx.StaticBoxSizer(wx.VERTICAL, self, '박스')
button_sizer = wx.GridSizer(5, 4, 0, 0)
# button_sizer = wx.FlexGridSizer(5, 4, 0, 0)
# button_sizer = wx.GridBagSizer(5, 4)
self.button = wx.Button(self, id=1, label='버튼')
self.button2 = wx.Button(self, id=2, label='버튼2')
self.Bind(wx.EVT_BUTTON, self.ButtonClick, id=1)
# self.Bind(wx.EVT_BUTTON, self.ButtonClick, self.button)
menu_bar = wx.MenuBar()
menu = wx.Menu()
menu_bar.Append(menu, '메뉴')
menu.Append(101, '하위 메뉴')
menu.Append(102, '종료')
self.SetMenuBar(menu_bar)
self.Bind(wx.EVT_MENU, self.MenuClick, id=101)
self.Bind(wx.EVT_MENU, self.Quit, id=102)
sizer.Add(self.button, 0, wx.ALL, 5)
sizer.Add(self.button2, 0, wx.ALL, 5)
sizer.Add(button_sizer, 1, wx.EXPAND, 5)
# button_sizer.AddGrowableCol(1)
# button_sizer.AddGrowableRow(1)
for i in range(20):
button = wx.Button(self, label='버튼')
button_sizer.Add(button)
# button_sizer.Add(button, (i * 2, i * 2), (2, 2), wx.EXPAND)
self.SetSizer(sizer)
def ButtonClick(self, event):
dialog = wx.MessageDialog(self, '정말로 누르셨습니까?', '확인', wx.YES_NO)
# dialog.ShowModal()
if dialog.ShowModal() == wx.ID_YES:
print("예")
else:
print("아니오")
dialog.Destroy()
def MenuClick(self, event):
dialog = wx.MessageDialog(self, '메뉴를 누르셨습니다', '메뉴', wx.OK)
dialog.ShowModal()
dialog.Destroy()
def Quit(self, event):
dialog = wx.MessageDialog(self, '종료하시겠습니까?', '종료', wx.CANCEL)
if dialog.ShowModal() == wx.ID_OK:
quit(0)
else:
pass
dialog.Destroy()
def run():
app = wx.App()
frame = Mainframe(None, -1, 'Calculator')
frame.Show()
app.MainLoop()
run()
'파이썬 강의 > wx' 카테고리의 다른 글
파이썬 GUI(wxPython) 7. 문자 표현 : StaticText / TextCtrl (0) | 2021.01.19 |
---|---|
파이썬 GUI(wxPython) 5. Sizer(레이아웃) : BoxSizer, StaticBoxSizer (0) | 2021.01.05 |
파이썬 GUI(wxPython) 4. 다이얼로그 (0) | 2021.01.05 |
파이썬 GUI(wxPython) 3. 메뉴바와 메뉴 (0) | 2021.01.05 |
파이썬 GUI(wxPython) 2. 버튼과 버튼이벤트 (1) | 2021.01.04 |