wx.TextCtrl is blank for very long strings - python-2.7

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/

Related

I am trying to have fixed frame for my GUI Application. The window should not change its size

I am trying to develop a GUI using Tkinter and Python2.7 by following a few tutorials and their documentation. Right now i am stuck on how to keep my frame a constant size (Because i want to have a nice background).
I have tried to use geometry() function from their documentation but always returns with an error - geometry attribute not found
import Tkinter as tk
import ttk
class Application(tk.Tk):
def __init__(self, *args, **kwargs):
# Initialize Tkinter
tk.Tk.__init__(self, *args, **kwargs)
tk.Tk.wm_title(self, "ScraperBot")
tk.Tk.geometry('250x250')
# Make a container
container = tk.Frame(self)
container.pack(side="top", fill="both", expand=True)
container.grid_rowconfigure(0, weight=1)
container.grid_columnconfigure(0, weight=1)
# Define Frames
self.frames = {}
for myFrame in (HomePage, PageOne, PageTwo):
frame = myFrame(container, self)
self.frames[myFrame] = frame
frame.grid(row=0, column=0, sticky="nsew")
# Which frame do we wanna display?
self.show_frame(HomePage)
def show_frame(self, cont):
frame = self.frames[cont]
frame.tkraise()
class HomePage(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
# Make a Label
label = ttk.Label(self, text="HomePage", font=LARGE_FONT)
label.pack(pady=10, padx=10) # Padding on top and bottom
# Add a Button to navigate from one page to another
button1 = tk.Button(self, text="Go to Page_1", fg="red",
command= lambda: controller.show_frame(PageOne))
button1.pack()
# Add a Button to navigate from one page to another
button6 = tk.Button(self, text="Go to Page_2", fg="green",
command= lambda: controller.show_frame(PageTwo))
button6.pack()
def button_Function(parameter):
print(parameter)
app = Application()
app.mainloop()

How to get the item in list view using with enter key

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_())

wxpython - responding to MessageDialogs and FileDialogs within a frame during unit-testing

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()

How to change a content in a window in PySide?

I want to click on a menubar "Tools" menu to change my window content completely. How do I do this with PySide? Should I call QAction and set new widget as a central one with a parent of an old window? I'm beginner in python and english too. So far I've created only one-window application.
Firstly, I would define each tool within its own subclass of a QWidget. Secondly, I would add an instance of each tool widget thus created to the layout of the central widget of the main window. Finally, I would add actions to the menuBar and connect them to methods to show and hide the tools as desired.
Below is an example to show how this can be done with 2 different tools:
from PySide import QtGui
import sys
class myApplication(QtGui.QMainWindow):
def __init__(self, parent=None):
super(myApplication, self).__init__(parent)
self.setWindowTitle('No Tool is Selected')
#---- create instance of each tool widget ----
self.tool1 = Tool1(self)
self.tool2 = Tool2(self)
#---- layout for central widget ----
centralWidget = QtGui.QWidget()
centralLayout = QtGui.QGridLayout()
centralLayout.addWidget(self.tool1, 0, 0)
centralLayout.addWidget(self.tool2, 1, 0)
centralWidget.setLayout(centralLayout)
self.setCentralWidget(centralWidget)
#---- set the menu bar ----
contentMenu = self.menuBar().addMenu(("Tools"))
contentMenu.addAction('show Tool 1', self.show_Tool1)
contentMenu.addAction('show Tool 2', self.show_Tool2)
contentMenu.addAction('show All', self.show_All)
def show_Tool1(self):
self.tool1.show()
self.tool2.hide()
self.setWindowTitle('Tool #1 is Selected')
def show_Tool2(self):
self.tool1.hide()
self.tool2.show()
self.setWindowTitle('Tool #2 is Selected')
def show_All(self):
self.tool1.show()
self.tool2.show()
self.setWindowTitle('All Tools are Selected')
class Tool1(QtGui.QWidget):
def __init__(self, parent=None):
super(Tool1, self).__init__(parent)
layout = QtGui.QGridLayout()
layout.addWidget(QtGui.QPushButton('Tool #1'))
self.setLayout(layout)
self.hide()
class Tool2(QtGui.QWidget):
def __init__(self, parent=None):
super(Tool2, self).__init__(parent)
layout = QtGui.QGridLayout()
layout.addWidget(QtGui.QTextEdit('Tool #2'))
self.setLayout(layout)
self.hide()
if __name__ == '__main__':
app = QtGui.QApplication(sys.argv)
instance = myApplication()
instance.show()
sys.exit(app.exec_())
Which results in:

Mouse events in PyQt5 and PyQt4

I used to have an application in PyQt5, where user could move QGroupBox widget, by pressing mouse button and simply move it. In PyQt5 it works perfectly, but I had to refuse PyQt5 for some reasons and use PyQt4 instead of it. But now I can move my QgroupBox widget only after double click. I use the same piece of code, but in PyQt5 it worked after one click and now only after second one (after first click the whole application's window starts to move). What should I add/edit in order to reach the same result like in PyQt5?
from PyQt4.QtGui import *
from PyQt4.QtCore import *
class WidgetPattern(QGroupBox):
def __init__(self, name, parent=None):
super(WidgetPattern, self).__init__(parent=parent)
self.layout = QVBoxLayout(self)
self._offset = 0
self.widgetLength = 280
self.name = QLabel(parent=self)
self.name.setText(name)
self.name.adjustSize()
self.name.move(self.widgetLength / 2 - self.name.width() / 2, 5)
self.close_button = QToolButton(parent=self)
self.close_button.resize(24, 24)
self.close_button.setAutoRaise(True)
self.close_button.move(self.widgetLength - self.close_button.width(), 0)
self.close_button.setIcon(QIcon.fromTheme("application-exit"))
self.setFixedSize(280, 60)
def mousePressEvent(self, event):
self._offset = event.pos()
def mouseMoveEvent(self, event):
self.move(
QGroupBox.mapToParent(
self,
event.pos() -
self._offset))
class ConcertGUI(QWidget):
def __init__(self, parent=None):
super(ConcertGUI, self).__init__(parent)
widget=WidgetPattern("test")
self._main_layout = QVBoxLayout()
self._main_layout.addWidget(widget, 0)
self.setLayout(self._main_layout)
self.resize(1024, 500)
if __name__ == '__main__':
import sys
app = QApplication(sys.argv)
gui = ConcertGUI()
gui.show()
sys.exit(app.exec_())