Below is screenshot of the error. Why does it happen?
This is probably what you are trying to achieve. Although when posting to StackOverflow you should cut and paste your code into the question and not put it in a link, especially a link that is an image.
Few people will make the effort to help, if you make it difficult for them to do so.
import wx
class MyApp(wx.App):
def OnInit(self):
self.frame = MyFrame()
self.SetTopWindow(self.frame)
return True
class MyFrame(wx.Frame):
def __init__(self):
wx.Frame.__init__(self,None, title="Window", pos = (100,150), size =(250,200))
menu = wx.Menu()
menu.Append(1,'&About')
menu.AppendSeparator()
menu.Append(2,'E&xit')
menuBar = wx.MenuBar()
menuBar.Append(menu,'&File')
self.Bind(wx.EVT_MENU, self.OnAbout, id=1)
self.Bind(wx.EVT_MENU, self.OnExit, id=2)
self.SetMenuBar(menuBar)
self.Layout()
self.Show()
def OnExit(self, evt):
self.Destroy()
def OnAbout(self, evt):
print("This is MyFrame")
if __name__ == "__main__":
app = MyApp()
app.MainLoop()
I can't figure out how you even ran that code because your if __name__ == '__main__' and you main method are indented inside your myFrame class. Try out-indenting it I mean your end of code should be like:
def main():
app = myApp()
app.MainLoop()
if __name__ == '__main__':
main()
also, your naming convention is not pythonic.
Python recommends UpperCamelCase for class names, CAPITALIZED_WITH_UNDERSCORES for constants, and lowercase_separated_by_underscores for other names.
Related
In my program i want to use key press event in list view.When i press the enter key then only my selected text will print..Can any one please tell me how to use key press event for list view.I tried with installEventFilter but this method showing non type error.
Given below is my code:
import sys
from PyQt4 import QtCore,QtGui
class List_View(QtGui.QMainWindow):
def __init__(self, parent=None):
super(List_View, self).__init__(parent)
self.listview = QtGui.QListView()
model = QtGui.QStandardItemModel(self.listview)
for i in ['linux', 'windows', 'mac os']:
model.appendRow(QtGui.QStandardItem(i))
self.listview.setModel(model)
self.listview.entered.connect(self.add_items)
widget = QtGui.QWidget()
self.setCentralWidget(widget)
vlay = QtGui.QVBoxLayout(widget)
vlay.addWidget(self.listview)
self.resize(400, 200)
def add_items(self):
pass #here i need to print particular item in list view
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
w = List_View()
w.show()
sys.exit(app.exec_())
I think you have not read the docs of the entered signal or you have not understood it, that signal only triggers when the mouse is on the item but for this you must activate the mouse tracking with self.listview.setMouseTracking(True)
A simple solution is to use a QShortcut:
import sys
from PyQt4 import QtCore,QtGui
class List_View(QtGui.QMainWindow):
def __init__(self, parent=None):
super(List_View, self).__init__(parent)
shorcut = QtGui.QShortcut(
QtGui.QKeySequence(QtCore.Qt.Key_Return),
self
)
shorcut.activated.connect(self.on_enter_pressed)
self.listview = QtGui.QListView()
model = QtGui.QStandardItemModel(self.listview)
for i in ['linux', 'windows', 'mac os']:
model.appendRow(QtGui.QStandardItem(i))
self.listview.setModel(model)
widget = QtGui.QWidget()
self.setCentralWidget(widget)
vlay = QtGui.QVBoxLayout(widget)
vlay.addWidget(self.listview)
self.resize(400, 200)
#QtCore.pyqtSlot()
def on_enter_pressed(self):
print("enter press")
ix = self.listview.selectionModel().currentIndex()
print(ix.data())
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
w = List_View()
w.show()
sys.exit(app.exec_())
Here is my sample code.When i click the ok button i need to change my cursor position to another line edit.How can i change my cursor position in the sample code.Can any one please help me.
Given below is my code:
import sys
from PyQt4 import QtGui
class Example(QtGui.QWidget):
def __init__(self):
super(Example, self).__init__()
self.initUI()
def initUI(self):
self.vbox = QtGui.QVBoxLayout()
self.le1 = QtGui.QLineEdit()
self.le2 = QtGui.QLineEdit()
self.le3 = QtGui.QLineEdit()
self.ok = QtGui.QPushButton("OK")
self.ok.clicked.connect(self.moving_position)
self.vbox.addWidget(self.le1)
self.vbox.addWidget(self.le2)
self.vbox.addWidget(self.le3)
self.vbox.addWidget(self.ok)
self.setLayout(self.vbox)
self.show()
def moving_position(self):
pass
#how to move cursor to next line edit
def main():
app = QtGui.QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())
if __name__ == '__main__':
main(
Give this a try: self.le1.setFocus()
I would like to test a GUI I have been working on written using wxpython without requiring interaction so that I can continue development and test regularly and easily. My problem is that whenever I test a function that opens a modal dialog the testing pauses and won't continue until I manually press the OK button. I can't seem to discover a reason for this, but it is connected to the native wxpython dialog types like wx.MessageDialog and wx.FileDialog because if I use show modal on a custom class that inherits from wx.Dialog then I can use wx.CallAfter to respond to the dialog fine. So is there a good way to respond to these modal dialogs?
The dialogs don't work during normal operation of the GUI if I just use Show instead of ShowModal so I can't simply not make the dialogs modal.
Bellow is a bit of code to test this outlining this basic problem. It runs two tests one that opens a wx.MessageDialog and one that opens a custom dialog both I attempt to close with wx.CallAfter.
import unittest
import wx
class MyDialog(wx.Dialog):
def __init__(self, parent):
wx.Dialog.__init__(self, parent, -1, 'Test')
wx.Button(self, wx.ID_OK)
class MyFrame(wx.Frame):
def __init__(self, parent, id):
wx.Frame.__init__(self, parent, id, 'Flintstones',
size=(340, 200))
panel = wx.Panel(self)
panel.SetBackgroundColour("White")
self.Bind(wx.EVT_CLOSE, self.OnCloseWindow)
self.button = wx.Button(panel, id=-1, label='custom dlg', size=(75, 25))
self.Bind(wx.EVT_BUTTON, self.create_dlg, self.button)
self.msgbutton = wx.Button(panel, id=-1, label='wx message dlg', size=(75, 25))
self.Bind(wx.EVT_BUTTON, self.create_msgdlg, self.msgbutton)
def OnCloseWindow(self, event):
self.Destroy()
def create_dlg(self, event):
TEXT="specimens interpretations are saved"
self.dlg = MyDialog(self)
result = self.dlg.ShowModal()
if result == wx.ID_OK:
print("custom dlg: okay pressed")
else:
print("custom: okay not pressed")
self.dlg.Destroy()
def create_msgdlg(self, event):
TEXT="specimens interpretations are saved"
self.dlg = wx.MessageDialog(self, caption="Saved",message=TEXT,style=wx.OK|wx.CANCEL)
result = self.dlg.ShowModal()
if result == wx.ID_OK:
print("message dlg: okay pressed")
else:
print("message dlg: okay not pressed")
self.dlg.Destroy()
class TestMyDialog(unittest.TestCase):
def setUp(self):
self.app = wx.App()
self.frame = MyFrame(None,1)
self.frame.Show()
def tearDown(self):
wx.CallAfter(self.app.Exit)
self.app.MainLoop()
def testDialog(self):
evt = wx.CommandEvent(wx.EVT_BUTTON.typeId,self.frame.button.GetId())
def clickOK():
clickEvent = wx.CommandEvent(wx.wxEVT_COMMAND_BUTTON_CLICKED, wx.ID_OK)
self.frame.dlg.ProcessEvent(clickEvent)
wx.CallAfter(clickOK)
self.frame.ProcessEvent(evt)
def testMsgDialog(self):
evt = wx.CommandEvent(wx.EVT_BUTTON.typeId,self.frame.msgbutton.GetId())
def clickOK():
clickEvent = wx.CommandEvent(wx.wxEVT_COMMAND_BUTTON_CLICKED, wx.ID_OK)
self.frame.dlg.ProcessEvent(clickEvent)
wx.CallAfter(clickOK)
self.frame.ProcessEvent(evt)
if __name__ == '__main__':
unittest.main()
I'm trying to display the string representation of a list of many float items in a wx.TextCtrl using the SetValue() method.
As soon as the length of the string to be displayed reaches 6151 characters the TextCtrl goes blank and does not display the string. I can still copy portions of the text control as normal and paste them somewhere (such as a text editor) but the characters in the text control itself don't appear on the screen.
Why isn't the text control's value displayed in the text control?
How do I make it display the string if it's longer than 6150 characters?
This happens when setting the text control's value using the SetValue method and when typing in the text control.
Changing the max length for the text control didn't help.
Environment:
Windows 10 (64 bit)
Python 2.7.10
wxPython 3.0
Example code:
import wx
import os
class MainWindow(wx.Frame):
def __init__(self, parent, title):
wx.Frame.__init__(self, parent, title=title, size=(200,-1))
self.control = wx.TextCtrl(self)
self.control.SetMaxLength(10000) #doesn't help
self.sizer = wx.BoxSizer(wx.VERTICAL)
self.sizer.Add(self.control, 1, wx.EXPAND)
self.SetSizer(self.sizer)
self.SetAutoLayout(1)
self.sizer.Fit(self)
self.Show(True)
app = wx.App(False)
frame = MainWindow(None, "Sample editor")
app.MainLoop()
It looks like a bug. According to the this, it should max out at 64K since Windows 98 unless the operating system you have has some kind of odd limit. You can actually increase the number of characters displayed by using one of the wx.TE_RICH style flags.
I was able to replicate your issue on Windows 7 with Python 2.7 and wxPython 3.0.2 using the following code:
import wx
########################################################################
class MyPanel(wx.Panel):
""""""
#----------------------------------------------------------------------
def __init__(self, parent):
"""Constructor"""
super(MyPanel, self).__init__(parent)
self.text = wx.TextCtrl(self, value="y"*7000)
btn = wx.Button(self, label='Line Length')
btn.Bind(wx.EVT_BUTTON, self.onLength)
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(self.text, 0, wx.EXPAND|wx.ALL, 5)
sizer.Add(btn, 0, wx.CENTER|wx.ALL, 5)
self.SetSizer(sizer)
#----------------------------------------------------------------------
def onLength(self, event):
""""""
print len(self.text.GetValue())
########################################################################
class MyFrame(wx.Frame):
""""""
#----------------------------------------------------------------------
def __init__(self):
"""Constructor"""
super(MyFrame, self).__init__(parent=None, title='Test')
panel = MyPanel(self)
self.Show()
if __name__ == '__main__':
app = wx.App(False)
frame = MyFrame()
app.MainLoop()
If I add the wx.TE_RICH flag and call Layout(), I can make it work though:
import wx
########################################################################
class MyPanel(wx.Panel):
""""""
#----------------------------------------------------------------------
def __init__(self, parent):
"""Constructor"""
super(MyPanel, self).__init__(parent)
self.text = wx.TextCtrl(self, value="y"*7000, style=wx.TE_RICH)
btn = wx.Button(self, label='Line Length')
btn.Bind(wx.EVT_BUTTON, self.onLength)
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(self.text, 0, wx.EXPAND|wx.ALL, 5)
sizer.Add(btn, 0, wx.CENTER|wx.ALL, 5)
self.SetSizer(sizer)
self.Layout()
#----------------------------------------------------------------------
def onLength(self, event):
""""""
print len(self.text.GetValue())
########################################################################
class MyFrame(wx.Frame):
""""""
#----------------------------------------------------------------------
def __init__(self):
"""Constructor"""
super(MyFrame, self).__init__(parent=None, title='Test')
panel = MyPanel(self)
self.Show()
if __name__ == '__main__':
app = wx.App(False)
frame = MyFrame()
app.MainLoop()
You should report this bug here: http://trac.wxwidgets.org/
I've been having difficulty with my PySide program for a few days now. I don't think the problem is incredibly difficult because there are answer out there. Problem I have is none of them seem to work for me.
I want to 'listen' to the file objects stdout and stderr and output the contents to QText Edit widget while my PySide program is running. Now, I already realise this question (or something similar) has been asked before on here but like I said, can't get it to work for me for some reason and most other solutions out there are based on the one that I can't get working, so a very frustrating last few days for me. This solution (OutLog), is included in my code snippet below, just in case one of you guys can see a botched implementation on my part.
Things to remember:
1 I'm doing this on Windows 7(duuuh, da, da, duh)
2 I'm using eclipse and running it from inside the IDE(duh, da, da, duh, DUUUUH: It would be really handy if the suggestions worked with either commandline or an IDE)
3 I really just want to duplicate the output of stdout and stderr to the widget while the program runs. For this to happen line-by-line would be a dream but even if it all comes out as a chunk at the end of a loop or something, that would be fab.
4 Oh, and also regarding OutLog, could somebody tell me how, if self.out is set to 'None' in the init, this class can actually work? I mean, self.out is always a NoneType object, right???
Any help would be appreciated, even if it's just pointers to where I could find more information. I've been trying to build my own solution (I'm a bit of a sadist that way) but I've found it hard to find relevant info on how these objects work to do that.
Anyway, whine over. Here's my code:
#!/usr/bin/env python
import sys
import logging
import system_utilities
log = logging.getLogger()
log.setLevel("DEBUG")
log.addHandler(system_utilities.SystemLogger())
import matplotlib
matplotlib.use("Qt4Agg")
matplotlib.rcParams["backend.qt4"] = "PySide"
import subprocess
import plot_widget
from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.figure import Figure
from PySide import QtCore, QtGui
class MainWindow(QtGui.QMainWindow):
"""This is the main window class and displays the primary UI when launched.
Inherits from QMainWindow.
"""
def __init__(self):
"""Init function.
"""
super(MainWindow, self).__init__()
self.x = None
self.y = None
self.data_plot = None
self.plot_layout = None
self.terminal = None
self.setup_plot()
self.setup_interface()
def setup_plot(self):
"""Member function to setup the graph window in the main UI.
"""
#Create a PlotWidget object
self.data_plot = plot_widget.PlotWidget()
#Create a BoxLayout element to hold PlotWidget
self.plot_layout = QtGui.QVBoxLayout()
self.plot_layout.addWidget(self.data_plot)
def setup_interface(self):
"""Member function to instantiate and build the composite elements of the
UI."""
#Main widget houses layout elements (Layout cannot be placed directly in a QMainWindow).
central_widget = QtGui.QWidget()
test_splitter = QtGui.QSplitter(QtCore.Qt.Vertical)
button_splitter = QtGui.QSplitter(QtCore.Qt.Horizontal)
#UI BoxLayout elements
central_layout = QtGui.QVBoxLayout()
#button_layout = QtGui.QHBoxLayout()
#UI PushButton elements
exit_button = QtGui.QPushButton("Close")
run_button = QtGui.QPushButton("Run...")
#UI Text output
self.editor = QtGui.QTextEdit()
self.editor.setReadOnly(True)
self.terminal = QtGui.QTextBrowser()
self.terminal.setReadOnly(True)
#UI PushButton signals
run_button.clicked.connect(self.run_c_program)
run_button.clicked.connect(self.data_plot.redraw_plot)
exit_button.clicked.connect(QtCore.QCoreApplication.instance().quit)
#Build the UI from composite elements
central_layout.addLayout(self.plot_layout)
central_layout.addWidget(self.editor)
button_splitter.addWidget(run_button)
button_splitter.addWidget(exit_button)
test_splitter.addWidget(button_splitter)
test_splitter.addWidget(self.terminal)
test_splitter.setCollapsible(1, True)
central_layout.addWidget(test_splitter)
central_widget.setLayout(central_layout)
self.setCentralWidget(central_widget)
self.show()
class OutLog:
def __init__(self, edit, out=None, color=None):
"""(edit, out=None, color=None) -> can write stdout, stderr to a
QTextEdit.
edit = QTextEdit
out = alternate stream ( can be the original sys.stdout )
color = alternate color (i.e. color stderr a different color)
"""
self.edit = edit
self.out = None
self.color = color
def write(self, m):
if self.color:
tc = self.edit.textColor()
self.edit.setTextColor(self.color)
self.edit.moveCursor(QtGui.QTextCursor.End)
log.debug("this is m {}".format(m))
self.edit.insertPlainText( m )
if self.color:
self.edit.setTextColor(tc)
if self.out:
self.out.write(m)
def main():
app = QtGui.QApplication(sys.argv)
log.debug("Window starting.")
window = MainWindow()
sys.stdout = OutLog(window.terminal, sys.stdout)
sys.stderr = OutLog(window.terminal, sys.stderr, QtGui.QColor(255,0,0))
window.show()
sys.exit(app.exec_())
log.info("System shutdown.")
if __name__ == '__main__':
main()
"Help me Obi-Wan..."
Thanks in advance guys (and gals :-))
It seems that all you need to do is override sys.stderr and sys.stdout with a wrapper object that emits a signal whenever output is written.
Below is a demo script that should do more or less what you want. Note that the wrapper class does not restore sys.stdout/sys.stderr from sys.__stdout__/sys.__stderr__, because the latter objects may not be same as the ones that were orignally replaced.
PyQt5:
import sys
from PyQt5 import QtWidgets, QtGui, QtCore
class OutputWrapper(QtCore.QObject):
outputWritten = QtCore.pyqtSignal(object, object)
def __init__(self, parent, stdout=True):
super().__init__(parent)
if stdout:
self._stream = sys.stdout
sys.stdout = self
else:
self._stream = sys.stderr
sys.stderr = self
self._stdout = stdout
def write(self, text):
self._stream.write(text)
self.outputWritten.emit(text, self._stdout)
def __getattr__(self, name):
return getattr(self._stream, name)
def __del__(self):
try:
if self._stdout:
sys.stdout = self._stream
else:
sys.stderr = self._stream
except AttributeError:
pass
class Window(QtWidgets.QMainWindow):
def __init__(self):
super().__init__( )
widget = QtWidgets.QWidget(self)
layout = QtWidgets.QVBoxLayout(widget)
self.setCentralWidget(widget)
self.terminal = QtWidgets.QTextBrowser(self)
self._err_color = QtCore.Qt.red
self.button = QtWidgets.QPushButton('Test', self)
self.button.clicked.connect(self.handleButton)
layout.addWidget(self.terminal)
layout.addWidget(self.button)
stdout = OutputWrapper(self, True)
stdout.outputWritten.connect(self.handleOutput)
stderr = OutputWrapper(self, False)
stderr.outputWritten.connect(self.handleOutput)
def handleOutput(self, text, stdout):
color = self.terminal.textColor()
self.terminal.moveCursor(QtGui.QTextCursor.End)
self.terminal.setTextColor(color if stdout else self._err_color)
self.terminal.insertPlainText(text)
self.terminal.setTextColor(color)
def handleButton(self):
if QtCore.QTime.currentTime().second() % 2:
print('Printing to stdout...')
else:
print('Printing to stderr...', file=sys.stderr)
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
window = Window()
window.setGeometry(500, 300, 300, 200)
window.show()
sys.exit(app.exec_())
PyQt4:
import sys
from PyQt4 import QtGui, QtCore
class OutputWrapper(QtCore.QObject):
outputWritten = QtCore.pyqtSignal(object, object)
def __init__(self, parent, stdout=True):
QtCore.QObject.__init__(self, parent)
if stdout:
self._stream = sys.stdout
sys.stdout = self
else:
self._stream = sys.stderr
sys.stderr = self
self._stdout = stdout
def write(self, text):
self._stream.write(text)
self.outputWritten.emit(text, self._stdout)
def __getattr__(self, name):
return getattr(self._stream, name)
def __del__(self):
try:
if self._stdout:
sys.stdout = self._stream
else:
sys.stderr = self._stream
except AttributeError:
pass
class Window(QtGui.QMainWindow):
def __init__(self):
QtGui.QMainWindow.__init__(self)
widget = QtGui.QWidget(self)
layout = QtGui.QVBoxLayout(widget)
self.setCentralWidget(widget)
self.terminal = QtGui.QTextBrowser(self)
self._err_color = QtCore.Qt.red
self.button = QtGui.QPushButton('Test', self)
self.button.clicked.connect(self.handleButton)
layout.addWidget(self.terminal)
layout.addWidget(self.button)
stdout = OutputWrapper(self, True)
stdout.outputWritten.connect(self.handleOutput)
stderr = OutputWrapper(self, False)
stderr.outputWritten.connect(self.handleOutput)
def handleOutput(self, text, stdout):
color = self.terminal.textColor()
self.terminal.moveCursor(QtGui.QTextCursor.End)
self.terminal.setTextColor(color if stdout else self._err_color)
self.terminal.insertPlainText(text)
self.terminal.setTextColor(color)
def handleButton(self):
if QtCore.QTime.currentTime().second() % 2:
print('Printing to stdout...')
else:
sys.stderr.write('Printing to stderr...\n')
if __name__ == '__main__':
app = QtGui.QApplication(sys.argv)
window = Window()
window.setGeometry(500, 300, 300, 200)
window.show()
sys.exit(app.exec_())
NB:
Instances of the OutputWrapper should be created as early as possible, so as to ensure that other modules that need sys.stdout/sys.stderr (such as the logging module) use the wrapped versions wherever necessary.
self.out = None is probably a typo and should be self.out = out. That way, you can see anything that printed in the console as well. This is the first step to be sure that the code prints anything at all.
The next thing is that you need to realize which output you're redirecting. A subprocess get its own stdio, so no amount of redirection of the parent's stdout is going to have any effect.
Getting stdio correct with a subprocess isn't trivial. I suggest to start with subprocess.communicate() which gives you all the output as a single string. That's usually good enough.