CheckBox Event in wxPython not working - events

I'm sorry if this is so simple, but I'm trying to bind an event to a checkbox in a menubar with wxPython. For some reason, it won't work! I've tried a variety of different ways to get it to print a statement, but nothing happens when I check the box. Is it not binding correctly? This is just a simple app I wrote to demonstrate the problem...
import wx
class Frame(wx.Frame):
def __init__(self, parent, id, title):
wx.Frame.__init__(self, parent, id, title)
panel = wx.Panel(self)
menuBar = wx.MenuBar()
menu = wx.Menu()
self.checkbox = menu.AppendCheckItem(-1, "Check me")
menuBar.Append(menu,'&check box')
self.SetMenuBar(menuBar)
self.Bind(wx.EVT_CHECKBOX, self.onCheck, self.checkbox)
def onCheck(self, e):
print self.checkbox.IsChecked()
app = wx.App()
test = Frame(None, -1, "Test")
test.Show()
app.MainLoop()

I've figured it out. I needed to change the Bind event from wx.EVT_CHECKBOX to wx.EVT_MENU.

Related

wxPython build menus on MacBook

On a MacBook running MacOS Mojave 10.14.6, Python 3.7.4 and wxPython 4.0.6 I can't get menus to work when creating a GUI. Here's the code I'm using.
def basicGUI(self):
menuBar = wx.MenuBar()
fileButton = wx.Menu()
exitItem = fileButton.Append(wx.ID_EXIT, 'Exit', 'status msg..')
menuBar.Append(fileButton, 'File')
menuBar.Append(fileButton, 'Edit')
self.SetMenuBar(menuBar)
self.Bind(wx.EVT_MENU, self.Quit, exitItem)
self.SetTitle('Epic Window')
self.Show(True)
Creating the frame and panel is all OK. Any assistance would be appreciated. thanks
I don't own a mac, but running your code on windows produces an assertion error because you're adding the menu named 'fileButton' twice. If you comment out the line menuBar.Append(fileButton, 'Edit') your example should run. If you want to create an edit menu, don't reuse the file menu instance, create a new wx.Menu() instance.
import wx
class Frame(wx.Frame):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.basicGUI()
def basicGUI(self):
menuBar = wx.MenuBar()
fileButton = wx.Menu()
editmenu = wx.Menu()
exitItem = wx.MenuItem(fileButton, wx.ID_EXIT, "Exit")
edit_item = wx.MenuItem(editmenu, wx.ID_EDIT, "Edit")
fileButton.Append(exitItem)
editmenu.Append(edit_item)
menuBar.Append(fileButton, 'File')
menuBar.Append(editmenu, 'Edit')
self.SetMenuBar(menuBar)
self.Bind(wx.EVT_MENU, self.Quit, id=wx.ID_EXIT)
self.Bind(wx.EVT_MENU, self.on_edit, id=wx.ID_EDIT)
self.SetTitle('Epic Window')
self.CenterOnScreen(wx.BOTH)
self.Show(True)
def Quit(self, event):
self.Close()
def on_edit(self, event):
with wx.MessageDialog(self, "You clicked edit", "Caption", wx.ICON_INFORMATION) as dialog:
dialog.ShowModal()
app = wx.App()
frame = Frame(parent=None)
app.MainLoop()
Side Note:
It's helpful if you post a runnable example of your problem instead of just the excerpted method so we can see the problem in its full context instead of having to assume what the rest of your program looks like.

Multilpe screen in wxpython

all.
I'd like to be able to switch between multiple screens. Meaning, the first one is the main, then when with a button or an external switch is activated I can see the page #2, in that one I may have an other button to return to the first one, or going to #3, etc. Cause I have a main screen for a big RPM meter, but I may want to see instead all three meter on the same page, or view the raw data in an other page, or go to the set-up page or elsewhere in the future development. I'm using the full screen space for my graphic. Maybe something like "hide" or "show" a page with an event of some kind. I have a single class script for every pages so far, but unable to group them in a single one. Thanks for your help
I wrote about this concept several years ago here. I went ahead an reproduced the example from that article:
import wx
import wx.grid as gridlib
class PanelOne(wx.Panel):
""""""
def __init__(self, parent):
"""Constructor"""
wx.Panel.__init__(self, parent=parent)
txt = wx.TextCtrl(self)
class PanelTwo(wx.Panel):
""""""
def __init__(self, parent):
"""Constructor"""
wx.Panel.__init__(self, parent=parent)
grid = gridlib.Grid(self)
grid.CreateGrid(25,12)
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(grid, 0, wx.EXPAND)
self.SetSizer(sizer)
class MyForm(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, None, wx.ID_ANY,
"Panel Switcher Tutorial")
self.panel_one = PanelOne(self)
self.panel_two = PanelTwo(self)
self.panel_two.Hide()
self.sizer = wx.BoxSizer(wx.VERTICAL)
self.sizer.Add(self.panel_one, 1, wx.EXPAND)
self.sizer.Add(self.panel_two, 1, wx.EXPAND)
self.SetSizer(self.sizer)
menubar = wx.MenuBar()
fileMenu = wx.Menu()
switch_panels_menu_item = fileMenu.Append(wx.ID_ANY,
"Switch Panels",
"Some text")
self.Bind(wx.EVT_MENU, self.onSwitchPanels,
switch_panels_menu_item)
menubar.Append(fileMenu, '&File')
self.SetMenuBar(menubar)
def onSwitchPanels(self, event):
""""""
if self.panel_one.IsShown():
self.SetTitle("Panel Two Showing")
self.panel_one.Hide()
self.panel_two.Show()
else:
self.SetTitle("Panel One Showing")
self.panel_one.Show()
self.panel_two.Hide()
self.Layout()
# Run the program
if __name__ == "__main__":
app = wx.App(False)
frame = MyForm()
frame.Show()
app.MainLoop()
The basic idea here is to Hide() one panel and Show() another. You might also want to look at the Notebook controls that wxPython provides as they have a similar functionality.

bind menu events wxpython

I am new in Python, but I would like to understand the use of GUIs using wxpython. I am using a template for the creation of a frame and I added the menus. The menus are shown but they do not trigger any action, so I need to bind actions to the different menu items I created. Problem is, I don't know how.
I started with the menu save, which I called 'menu_open' and associated to the method
filemenu.Append(wx.ID_OPEN, "Open")
I associated an action using:
self.Bind(wx.EVT_MENU, self.Open, menu_open)
but I got the error:
AttributeError: 'MainWindow' object has no attribute 'Open'
If I try with 'OnOpen' (since there is an 'OnExit' attribute) I get the errors:
frame = MainWindow(None, "Sample editor")
AttributeError: 'MainWindow'object has no attribute 'OnOpen'
So the questions are:
is the self.Bind syntax correct and the right way to assign an action to a menu?
is there a complete list of attributes for the menus available in wxPython?
I am reporting the whole code for reference. Thanks. G.
#!/usr/bin/python
# -*- coding: utf-8 -*-
from __future__ import print_function
import wx
class MainWindow(wx.Frame):
def __init__(self, parent, title):
wx.Frame.__init__(self, parent, title=title, size=(200, 100))
self.control = wx.TextCtrl(self, style=wx.TE_MULTILINE)
# A Statusbar in the bottom of the window
self.CreateStatusBar()
# Setting up the menus
'''Define main items'''
filemenu = wx.Menu()
editmenu = wx.Menu()
infomenu = wx.Menu()
'''Items'''
# file menu
menu_open = filemenu.Append(wx.ID_OPEN, "Open")
filemenu.Append(wx.ID_NEW, "New")
filemenu.Append(wx.ID_SAVE, "Save")
filemenu.Append(wx.ID_SAVEAS, "Save as")
filemenu.Append(wx.ID_EXIT, "Exit")
filemenu.AppendSeparator()
filemenu.Append(wx.ID_PRINT, "&Print")
filemenu.Append(wx.ID_PRINT_SETUP, "Print setup")
filemenu.Append(wx.ID_PREVIEW, "Preview")
# edit menu
editmenu.Append(wx.ID_COPY, "Copy")
editmenu.Append(wx.ID_CUT, "Cut")
editmenu.Append(wx.ID_PASTE, "Paste")
editmenu.AppendSeparator()
editmenu.Append(wx.ID_UNDO, "Undo")
editmenu.Append(wx.ID_REDO, "Re-do it")
# info menu
infomenu.Append(wx.ID_ABOUT, "About")
'''Bind items for activation'''
# bind file menu
self.Bind(wx.EVT_MENU, self.OnOpen, menu_open)
# Creating the menubar.
menuBar = wx.MenuBar()
# Add menus
menuBar.Append(filemenu, "&File")
menuBar.Append(editmenu, "&Edit")
menuBar.Append(infomenu, "&Help")
# Adding the MenuBar to the Frame content.
self.SetMenuBar(menuBar)
self.Show(True)
app = wx.App(False)
frame = MainWindow(None, "Sample editor")
app.MainLoop()
You simply have not created the event handler method so when using
self.Bind(wx.EVT_MENU, self.OnOpen, menu_open)
you need a method that will be called added to the class MainWindow
def OnOpen(self, event):
print('OnOpen')

Works with QGridLayout not with QVBoxLayout

from PyQt4.QtCore import *
from PyQt4.QtGui import *
import sys, os, time
class SetName(QWidget):
def __init__(self):
QWidget.__init__(self)
self.show()
toplayout = QVBoxLayout()
self.setWindowTitle('Personal Info')
self.form_layout = QFormLayout()
self.setLayout(self.form_layout)
self.line_edit_param = QLineEdit(self)
self.line_edit_param.setPlaceholderText("Write Here")
self.form_layout.addRow('Write Name', self.line_edit_param)
toplayout.addLayout(self.form_layout)
self.setFocus()
class LearnApp(QDialog):
def __init__(self):
super(QDialog, self).__init__()
self.setWindowTitle("LearnApp")
self.active = False
close_button = QPushButton("Close")
close_button.clicked.connect(self.close)
self.check_button = QPushButton("Check")
self.check_button.clicked.connect(self.set_data)
self.tr = QTextEdit()
self.tr.setReadOnly(True)
# layout
layout = QHBoxLayout()
#layout.addWidget(self.button3)
sub_layout = QVBoxLayout()
sub_layout.addWidget(self.check_button)
sub_layout.addWidget(close_button)
layout.addLayout(sub_layout)
layout.addWidget(self.tr)
self.setLayout(layout)
self.setFocus()
def set_data(self):
print "in set_data"
SetName()
app = QApplication(sys.argv)
dialog = LearnApp()
dialog.show()
app.exec_()
This is the code I'm trying. If edit it with toplayout = QGridLayout(), program works fine but with toplayout = QVBoxLayout(), it gives message QLayout::addChildLayout: layout "" already has a parentand just flashes the new window. What could be the problem? How should I tackle this? I wanna use QVBoxLayout instead of QGridLayout
Firstly, the new window disappears straight away because you don't store a reference to it. You need to store a reference to the instance in your LearnApp class, or parent it to another Qt object outside of set_data() if you want it to stick around.
The error message regarding the layouts is not occurring because of your choice of layouts, but because you are calling
self.setLayout(self.form_layout)
and then
toplayout.addLayout(self.form_layout)
The first call assigns the layout to the instance of SetName, but in doing so also makes the instance the parent of self.form_layout. The second call is trying to add the same layout to toplayout and set it as the parent, but Qt sees that self.form_layout already has a parent (i.e. is being used elsewhere). This is what the error message is trying to tell you.
I suspect that instead of self.setLayout(self.form_layout), you intended to write something like
self.setLayout(toplayout)

wxPython ListCtrl OnClick Event

So, I have a wxPython ListCtrl which contains rows of data. How can I make an event that calls a function, with the row contents, when one of the rows if clicked on?
You can use the Bind function to bind a method to an event. For example,
import wx
class MainWidget(wx.Frame):
def __init__(self, parent, title):
super(MainWidget, self).__init__(parent, title=title)
self.list = wx.ListCtrl(parent=self)
for i,j in enumerate('abcdef'):
self.list.InsertStringItem(i,j)
self.Bind(wx.EVT_LIST_ITEM_ACTIVATED, self.OnClick, self.list)
self.Layout()
def OnClick(self, event):
print event.GetText()
if __name__ == '__main__':
app = wx.App(redirect=False)
frame = MainWidget(None, "ListCtrl Test")
frame.Show(True)
app.MainLoop()
This app will print the item in the ListCtrl that is activated (by pressing enter or double-clicking). If you just want to catch a single click event, you could use wx.EVT_LIST_ITEM_SELECTED.
The important point is that the Bind function specifies the method to be called when a particular event happens. See the section in the wxPython Getting Started guide on event handling. Also see the docs on ListCtrl for the events that widget uses.

Resources