Trouble with Box Sizers in WxPython - python-2.7

I've been trying to produce something that allows me to have multiple sentences in a line.
The code is:
import wx
app = wx.PySimpleApp()
class MyDialog(wx.Frame):
"""
This is my dialog in which I have my interface.
"""
def __init__(self):
"""
This stores all my variables.
"""
wx.Frame.__init__(self, None, -1, "Edit Action", size=(400, 300))
self.my_mini_panels = []
self.my_mini_hboxes = []
self.my_mini_vboxes = []
self.main_vbox = wx.BoxSizer(wx.VERTICAL)
self.main_hbox = wx.BoxSizer(wx.HORIZONTAL)
self.my_mini_panels.append(wx.Panel(self, -1, style=wx.SIMPLE_BORDER,
size=(400, 20)))
self.my_mini_hboxes.append(wx.BoxSizer(wx.HORIZONTAL))
self.my_mini_vboxes.append(wx.BoxSizer(wx.VERTICAL))
self.my_mini_hboxes[0].AddMany((wx.StaticText(self.my_mini_panels[0],
-1, 'Here it is... '),
wx.StaticText(self.my_mini_panels[0],
-1, 'There it was.')))
self.my_mini_panels.append(wx.Panel(self, -1, style=wx.SIMPLE_BORDER,
size=(400, 20)))
self.my_mini_hboxes.append(wx.BoxSizer(wx.HORIZONTAL))
self.my_mini_vboxes.append(wx.BoxSizer(wx.VERTICAL))
self.my_mini_hboxes[1].AddMany((wx.StaticText(self.my_mini_panels[1],
-1, 'Hello, '),
wx.StaticText(self.my_mini_panels[1],
-1, 'Goodbye!')))
for i, hbox in enumerate(self.my_mini_hboxes):
hbox.Add(self.my_mini_vboxes[i])
self.main_vbox.AddMany(tuple(self.my_mini_hboxes))
self.main_hbox.Add(self.main_vbox)
self.SetSizer(self.main_hbox)
if __name__ == '__main__':
dialog = MyDialog()
dialog.Show(True)
app.MainLoop()
It doesn't seem to be working. I'd like it to look like this:
What am I doing wrong?
EDIT
Perhaps I should make it clear that the static text objects must be separate. I can't just replace two segments of text on one line with one larger segment.

You don't need lots of sizers and panels for this. You can use one panel + one sizer + two static text widgets. Here's the code:
import wx
class MyDialog(wx.Frame):
"""
This is my dialog in which I have my interface.
"""
def __init__(self):
"""
This stores all my variables.
"""
wx.Frame.__init__(self, None, -1, "Edit Action", size=(400, 300))
panel = wx.Panel(self)
main_vbox = wx.BoxSizer(wx.VERTICAL)
label_one = wx.StaticText(panel, label="Here it is... There it was.")
label_two = wx.StaticText(panel, label="Hello, Goodbye!")
main_vbox.Add(label_one, 0, wx.ALL, 5)
main_vbox.Add(label_two, 0, wx.ALL, 5)
panel.SetSizer(main_vbox)
if __name__ == '__main__':
app = wx.App(False)
dialog = MyDialog()
dialog.Show(True)
app.MainLoop()
Note also that I changed your app object from wx.PySimpleApp to just wx.App. The wx.PySimpleApp has been deprecated and it is recommended to use wx.App from now on.
You might consider sub-classing from wx.Dialog instead of wx.Frame as that would make more sense if this is really supposed to be a dialog.

Related

How to print the variable of a class in python

I am trying to print the variable self.result. The ultimate goal is to use that for further processing, but for now just want to access the variable, so I chose it to print, however I am getting this message:
"wx._controls.StaticText; proxy of Swig Object of type 'wxStaticText *' at 0x23fed48> "
My code is below, any help is appreciated.
import wx
class ExampleFrame(wx.Frame):
def __init__(self, parent):
wx.Frame.__init__(self, parent)
self.panel = wx.Panel(self)
self.quote = wx.StaticText(self.panel, label="is Awesome")
self.result = wx.StaticText(self.panel, label="")
self.result.SetForegroundColour(wx.RED)
self.button = wx.Button(self.panel, label="Save")
self.lblname = wx.StaticText(self.panel, label="Your name:")
self.editname = wx.TextCtrl(self.panel, size=(140, -1))
# Set sizer for the frame, so we can change frame size to match widgets
self.windowSizer = wx.BoxSizer()
self.windowSizer.Add(self.panel, 1, wx.ALL | wx.EXPAND)
# Set sizer for the panel content
self.sizer = wx.GridBagSizer(5, 5)
self.sizer.Add(self.quote, (0, 1))
self.sizer.Add(self.result, (0, 0))
self.sizer.Add(self.lblname, (1, 0))
self.sizer.Add(self.editname, (1, 1))
self.sizer.Add(self.button, (2, 0), (1, 2), flag=wx.EXPAND)
# Set simple sizer for a nice border
self.border = wx.BoxSizer()
self.border.Add(self.sizer, 1, wx.ALL | wx.EXPAND, 5)
# Use the sizers
self.panel.SetSizerAndFit(self.border)
self.SetSizerAndFit(self.windowSizer)
# Set event handlers
self.button.Bind(wx.EVT_BUTTON, self.OnButton)
def OnButton(self, e):
self.result.SetLabel(self.editname.GetValue())
app = wx.App(False)
frame = ExampleFrame(None)
frame.Show()
print frame.result
app.MainLoop()
Your question makes no sense: Why would you want to read out the label of a static text? Its label (!, StaticText has no value) is set by the OnButton event, reading the value of the TextCtrl named editname (I think it is that what you are searching). But to answer your question: How to read a label from a StaticText change:
print frame.result
to
print frame.result.GetLabel() # or GetLabelText()
This will result in an empty string because the label is not set yet directly after frame creation.
See documentation parent object of StaticText.

Capture the current value in ComboBox. wxpython

In the code below I am trying to capture the current value of the ComboBox when the Save button is clicked.
Ive defined the function that is triggerd by the EVT_BUTTON that captures the values in the TextCtrl fields but does not work for ComboBox.
I've tried a few different approaches such as just trying to assign to audit_engineer = self.engineer_name.
Can anyone help me?
Regards
Paul.
class CreateAudit(wx.Panel):
def __init__(self, parent):
wx.Panel.__init__(self, parent)
self.lblname = wx.StaticText(self, label = "Site Name :", pos=(20,60))
self.site_name = wx.TextCtrl(self, value = "Enter site name here.", pos=(150, 60), size=(140,-1))
self.lblname = wx.StaticText(self, label = "Job Number", pos=(20,120))
self.job_number = wx.TextCtrl(self, value = "4 digit number only.", pos=(150, 120), size=(140,-1))
con = sqlite3.connect("hs_audit.sqlite")
con.row_factory = lambda cursor, row: row[0]
myList = con.execute('SELECT engineer FROM T1').fetchall()
self.lblname = wx.StaticText(self, label="Select Engineer :", pos=(20,180))
self.engineer_name = wx.ComboBox(self, pos=(150, 180), size=(140,-1)).SetItems(myList)
self.save_button =wx.Button(self, label="Save", pos=(150, 400))
self.save_button.Bind(wx.EVT_BUTTON, self.save_details)
self.Show()
def save_details(self, event):
audit_site = self.site_name.GetValue()
audit_engineer = self.engineer_name.GetValue() #<-- DOES NOT WORK NONE VALUE ERROR
audit_jobnumber = self.job_number.GetValue()
print audit_site
print audit_engineer
print audit_jobnumber
Changing
self.engineer_name = wx.ComboBox(self, pos=(150, 180), size=(140,-1)).SetItems(myList)
to
self.engineer_name = wx.ComboBox(self, pos=(170, 180), size=(170,-1), choices = myList)
Did the trick. Over complicated syntax in first effort I think.
Fixing these little things takes an age, but I'm enjoying the learning curve.

Keep a Frame in an other window Frame

My programm create a Frame with three panels in an horizontal boxsizer. A menu with "new window" item for create a seconde Frame. I give the seconde panel as parent of the seconde window. I wante the seconde Frame stays in the seconde panel area of my first frame.
if user move one of the two windows, the seconde stays in the panel screen area.
Do you know a way or something for that?
I tried a little something, but using is not very aesthetic.
and
import wx
class MainWindow(wx.Frame):
def __init__(self,parent,id):
wx.Frame.__init__(self,parent,id,'Python Test App',size=(600,400))
#Widgets
panel_gch = wx.Panel(self,-1,size = (150,-1))
panel_gch.SetBackgroundColour('white')
self.panel=wx.Panel(self,-1,size=(300,400))
self.panel.SetBackgroundColour((200,230,200))
panel_drt = wx.Panel(self,-1,size = (150,-1))
panel_drt.SetBackgroundColour('white')
box = wx.BoxSizer(wx.HORIZONTAL)
self.SetSizer(box)
#Add
box.Add(panel_gch,0,wx.EXPAND)
box.Add(self.panel,1,wx.EXPAND)
box.Add(panel_drt,0,wx.EXPAND)
#Menu
status=self.CreateStatusBar()
menubar=wx.MenuBar()
file_menu=wx.Menu()
ID_FILE_NEW = 1
file_menu.Append(ID_FILE_NEW,"New Window","This is a new window")
menubar.Append(file_menu,"File")
self.SetMenuBar(menubar)
#bind and layout
self.Bind(wx.EVT_MENU, self.get_new_window)
panel_gch.Layout()
self.panel.Layout()
panel_drt.Layout()
self.Layout()
def get_new_window(self,event): # create new window
self.new = NewWindow(self.panel,-1)
self.new.Show(True)
self.new.Bind(wx.EVT_MOVE,self.window2_on_move)
def window2_on_move(self,event): # Window2 must stay in
x, y = event.GetPosition()
v,w =self.panel.GetScreenPosition()
s,t = self.panel.GetClientSizeTuple()
if x < v:
self.new.Move((v,-1))
if y < w:
self.new.Move((-1,w))
if x+200 > v+s:
self.new.Move((v+s-200,-1))
if y+200 > w+t:
self.new.Move((-1,w+t-200))
class NewWindow(wx.MiniFrame):
def __init__(self,MainWindow,id):
wx.MiniFrame.__init__(self, MainWindow, id, 'New Window', size=(200,200),\
style = wx.MINIMIZE | wx.CAPTION | wx.CLOSE_BOX | wx.CLOSE_BOX)
self.CenterOnParent()
if __name__=='__main__':
app=wx.PySimpleApp()
frame=MainWindow(parent=None,id=-1)
frame.Show()
app.MainLoop()
What you probably want is AUI. I personally recommend the wx.lib.agw.aui set rather than wx.aui as the former is pure Python and has had a LOT more recent work done on it. There are multiple examples in the wxPython demo package. You can also read about it here:
http://wxpython.org/Phoenix/docs/html/lib.agw.aui.framemanager.AuiManager.html
Thanks you very much Mike, exactly what I needed.
With wxpython I found This way:
the child stays in the panel area and it follows the window parent when moving.
import wx
class MainWindow(wx.Frame):
def __init__(self,parent,id):
wx.Frame.__init__(self,parent,id,'Python Test App',size=(600,400))
self.new = None
#Widgets
self.position = (0,0)
panel_gch = wx.Panel(self,-1,size = (150,-1))
panel_gch.SetBackgroundColour('white')
self.panel=wx.Panel(self,-1,size=(300,400))
self.panel.SetBackgroundColour((200,230,200))
panel_drt = wx.Panel(self,-1,size = (150,-1))
panel_drt.SetBackgroundColour('white')
box = wx.BoxSizer(wx.HORIZONTAL)
self.SetSizer(box)
#Add
box.Add(panel_gch,0,wx.EXPAND)
box.Add(self.panel,1,wx.EXPAND)
box.Add(panel_drt,0,wx.EXPAND)
#Menu
status=self.CreateStatusBar()
menubar=wx.MenuBar()
file_menu=wx.Menu()
ID_FILE_NEW = 1
file_menu.Append(ID_FILE_NEW,"New Window","This is a new window")
menubar.Append(file_menu,"File")
self.SetMenuBar(menubar)
#bind and layout
self.Bind(wx.EVT_MENU, self.get_new_window)
panel_gch.Layout()
self.panel.Layout()
panel_drt.Layout()
self.Layout()
def get_new_window(self,event): # create new window
if self.new == None:
self.win_one_move = False
self.new = NewWindow(self.panel,-1)
self.new.Show(True)
self.new.Bind(wx.EVT_MOVE,self.window2_on_move)
self.Bind(wx.EVT_MOVE,self.window1_on_move)
v,w =self.GetPosition()
x, y = self.new.GetPosition()
self.get_windows_position((x-v),(y-w))
def get_windows_position(self,x,y):
self.position = (x,y)
print "check",self.position
def window2_on_move(self,event): # Window2 must stay in
if self.win_one_move == False:
x, y = event.GetPosition()
v,w =self.panel.GetScreenPosition()
s,t = self.panel.GetClientSizeTuple()
new_x,new_y = self.new.GetClientSizeTuple()
if x < v:
self.new.Move((v,-1))
if y < w:
self.new.Move((-1,w))
if x+new_x > v+s:
self.new.Move((v+s-new_x,-1))
if y+new_y > w+t:
self.new.Move((-1,w+t-new_y))
v,w =self.GetPosition()
x,y = self.new.GetPosition()
self.get_windows_position((x-v),(y-w))
if self.win_one_move == True:
self.win_one_move = False
def window1_on_move(self,event):
self.win_one_move = True
print "1 move"
x,y = self.GetPosition()
self.new.Move((x+self.position[0],y+self.position[1]))
print self.position
class NewWindow(wx.MiniFrame):
def __init__(self,MainWindow,id):
wx.MiniFrame.__init__(self, MainWindow, id, 'New Window', size=(200,200),\
style = wx.CAPTION | wx.CLOSE_BOX | wx.CLOSE_BOX)
self.CenterOnParent()
if __name__=='__main__':
app=wx.PySimpleApp()
frame=MainWindow(parent=None,id=-1)
frame.Show()
app.MainLoop()
Can be use by another.Thanks

How Do I Get A Bound Function Object from a wxPython Widget?

I have a script that allows the user to dynamically create fields. One of the fields is a button which opens up a dialog box for user input, the other two are text inputs. For the two text imputs, retrieving the user input was fairly simple and can be done by creating a list of all sizer objects in a sizer, then getting the widget object of each of these, then its value as shown below.
for sizerItem in sizer.GetChildren():
userInput = sizerItem.GetWindow().GetValue()
However, this breaks down if the widget is a button, because the button has no value. So what I need is something like GetWindow() that will return the function to which the widget object is bound. So then
exampleBtn = wx.Button(panel, -1, "Do Stuff")
self.Bind(wx.EVT_BUTTON, self.exampleFunc, exampleBtn) #with exampleFunc defined elsewhere
print exampleBtn.GetFunctions()
Would return:
['exampleFunc object']
EDIT: So here's a more proper explanation of what is going on here. There is a "row" of widgets that contains two text inputs, and one button. The button is bound to a function, the function creates a dialog box, and the user selects items from a list in this dialog box. The user can add/remove these rows of widgets at will (zero rows is possible). So what needs to happen is that the button in each row allows the items to be selected independently of other rows. This is already being done with the text input.
There doesn't appear to be a way to do this that's built into wxPython. However, when you create the button, you could create a data structure that keeps that information handy. Something like this, perhaps:
self.handlers = {}
self.count = 0
Ignore the count for now. Then in the method that creates the widget(s), you would do
self.handlers[exampleBtn: [] ]
self.handlers[exampleBtn].append(self.exampleFunc)
However, I would probably use a unique name when I create the buttons to use for the keys instead of the button object itself. So when you create the button, you'd do something like this:
exampleBtn = wx.Button(self, label="Test", name="btn%s" % self.count)
self.count += 1
Then you can create the handlers dict like this:
self.handlers[exampleBtn.GetName(): [] ]
self.handlers[exampleBtn.GetName()].append(self.exampleFunc)
This way you can check what functions it's attached to using
self.handlers["btn0"]
I hope all that rambling makes sense.
import wx
class MyDialog(wx.Dialog):
def __init__(self, parent):
wx.Dialog.__init__(self, parent, id=wx.ID_ANY, title="Get widget value", pos=wx.DefaultPosition,
size=wx.DefaultSize, style=wx.DEFAULT_DIALOG_STYLE)
self.SetSizeHints(wx.DefaultSize, wx.DefaultSize)
v_box = wx.BoxSizer(wx.VERTICAL)
self.panel = wx.Panel(self, wx.ID_ANY, wx.DefaultPosition, wx.Size(200, 300), wx.TAB_TRAVERSAL)
self.sizer_of_button_validator_and_chek_boxes = wx.BoxSizer(wx.VERTICAL)
self.button_validator = wx.Button(self.panel, wx.ID_ANY, u"call_validation", wx.DefaultPosition, wx.DefaultSize,
0)
self.button_validator.Bind(wx.EVT_BUTTON, self.call_validation)
self.sizer_of_button_validator_and_chek_boxes.Add(self.button_validator, 0, wx.ALL, 5)
lista = range(0, 5)
for number in lista:
name = 'check_box_' + str(number)
self.check_box = wx.CheckBox(self.panel, wx.ID_ANY, u"Check Me!", wx.DefaultPosition, wx.DefaultSize,
name=name)
self.sizer_of_button_validator_and_chek_boxes.Add(self.check_box, 0, wx.ALL, 5)
print(self.check_box.GetName())
self.panel.SetSizer(self.sizer_of_button_validator_and_chek_boxes)
self.panel.Layout()
self.sizer_of_button_validator_and_chek_boxes.Fit(self.panel)
v_box.Add(self.panel, 1, wx.EXPAND | wx.ALL, 5)
self.SetSizer(v_box)
self.Layout()
v_box.Fit(self)
self.Centre(wx.BOTH)
def call_validation(self,event):
children = self.sizer_of_button_validator_and_chek_boxes.GetChildren()
for child in children:
widget = child.GetWindow()
if isinstance(widget, wx.CheckBox):
print(widget.GetName(),widget.GetValue())
if __name__ == "__main__":
app = wx.App()
frame = MyDialog(None)
frame.Show()
app.MainLoop()

Center the Text of QTextEdit horizontally and vertically

I want to center the text of my QTextEdit horizontally and vertically.
I tried this, but it didn't work.
m_myTextEdit = new QTextEdit("text edit", m_ui->centralWidget);
m_myTextEdit->setGeometry(5, 50, 400, 250);
m_myTextEdit->setReadOnly(true);
m_myTextEdit->setAlignment(Qt::AlignCenter);
Is there a opportunity to set it centered with a StyleSheet?
If you only need one line, you can use a QLineEdit instead:
QLineEdit* lineEdit = new QLineEdit("centered text");
lineEdit->setAlignment(Qt::AlignCenter);
If you only want to display the text, not allow the user to edit it, you can use a QLabel instead. This works with line wrapping, too:
QLabel* label = new QLabel("centered text");
lineEdit->setWordWrap(true);
lineEdit->setAlignment(Qt::AlignCenter);
Here is code from PySide that I use for this, for those that need to use QTextEdit rather than QLineEdit. It is based on my answer here:
https://stackoverflow.com/a/34569735/1886357
Here is the code, but the explanation is at the link:
import sys
from PySide import QtGui, QtCore
class TextLineEdit(QtGui.QTextEdit):
topMarginCorrection = -4 #not sure why needed
returnPressed = QtCore.Signal()
def __init__(self, fontSize = 10, verticalMargin = 2, parent = None):
QtGui.QTextEdit.__init__(self, parent)
self.setAttribute(QtCore.Qt.WA_DeleteOnClose)
self.setLineWrapMode(QtGui.QTextEdit.NoWrap)
self.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
self.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
self.setFontPointSize(fontSize)
self.setViewportMargins(0, self.topMarginCorrection , 0, 0) #left, top, right, bottom
#Set up document with appropriate margins and font
document = QtGui.QTextDocument()
currentFont = self.currentFont()
currentFont.setPointSize(fontSize)
document.setDefaultFont(currentFont)
document.setDocumentMargin(verticalMargin)
self.setFixedHeight(document.size().height())
self.setDocument(document)
def keyPressEvent(self, event):
'''stops retun from returning newline'''
if event.key() in (QtCore.Qt.Key_Enter, QtCore.Qt.Key_Return):
self.returnPressed.emit()
event.accept()
else:
QtGui.QTextEdit.keyPressEvent(self, event)
def main():
app = QtGui.QApplication(sys.argv)
myLine = TextLineEdit(fontSize = 15, verticalMargin = 8)
myLine.show()
sys.exit(app.exec_())
if __name__ == "__main__":
main()