I am currently using wx.CustomTree, to use to display a series of configuration settings. I generally fill them with wx.TextCtrl / wx.Combobox, to allow the user to edit / enter stuff. Here is my code:
class ConfigTree(CT.CustomTreeCtrl):
"""
Holds all non gui drawing panel stuff
"""
def __init__(self, parent):
CT.CustomTreeCtrl.__init__(self, parent,
id = common.ID_CONTROL_SETTINGS,
style = wx.TR_DEFAULT_STYLE | wx.TR_HAS_BUTTONS
| wx.TR_HAS_VARIABLE_ROW_HEIGHT | wx.TR_SINGLE)
#self.HideWindows()
#self.RefreshSubtree(self.root)
self.population_size_ctrl = None
self.SetSizeHints(350, common.FRAME_SIZE[1])
self.root = self.AddRoot("Configuration Settings")
child = self.AppendItem(self.root, "Foo", wnd=wx.TextCtrl(self, wx.ID_ANY, "Lots Of Muffins"))
The problem is, any children nodes, the data for these nodes is not filled in. When i basically expand the configuration settings tree node. I see the "Foo" node, however the textbox is empty. This is the same for both text node, Until i actually click on the child node. I've looked tried every form of update / etc. Does anyone have any ideas?
To: Anurag Uniyal
Firstly sorry for not giving the rest of the code. I've gotten around this problem by simply resizing the window everytime i demo the application.
So i tried the code on my Macbook Pro running Mac OS X, with newest wx and python 2.6. I still have the same problem, however i noticed resizing the window, or even touching the scrollbar fixes the issue.
I also noticed however, there is absolutely NO problems running on Windows Vista / Windows 7.
So trying this on another macbook running an older version of wx + python. Results in the same problem :(
Is there anyway to force the panel to redraw it self? Which i am pretty sure happens when i resize the window.
If you don't have any ideas then i'll strip it down and make a demo example, im home and won't be at work until later tommorow.
You can use RefreshItems if you are using virtual controls, or you could refresh the panel, which would update the contents of all the children windows (widgets).
I tested it on window with wx version 2.8.10.1 and it works, which OS and wx version you are using?
here is self contained code, which can be copy-pasted and run
import wx
import wx.lib.customtreectrl as CT
class ConfigTree(CT.CustomTreeCtrl):
"""
Holds all non gui drawing panel stuff
"""
def __init__(self, parent):
CT.CustomTreeCtrl.__init__(self, parent,
id = -1,
style = wx.TR_DEFAULT_STYLE | wx.TR_HAS_BUTTONS
| wx.TR_HAS_VARIABLE_ROW_HEIGHT | wx.TR_SINGLE)
self.population_size_ctrl = None
self.SetSizeHints(350, 350)
self.root = self.AddRoot("Configuration Settings")
child = self.AppendItem(self.root, "Foo", wnd=wx.TextCtrl(self, wx.ID_ANY, "Lots Of Muffins"))
def main():
app = wx.App()
frame = wx.Frame(None, title="Test tree", size=(500,500))
p = wx.Panel(frame, size=(500,500))
tree = ConfigTree(p)
tree.SetSize((500,500))
frame.Show()
app.MainLoop()
if __name__ == '__main__':
main()
Related
I'm trying to create an application that contains a web browser within it, but when I add the web browser my menu bar visually disappears but functionally remains in place. The following are two images, one showing the "self.centralWidget(self.web_widget)" commented out, and the other allows that line to run. If you run the example code, you will also see that while visually the entire web page appears as if the menu bar wasn't present, you have to click slightly below each entry field and button in order to activate it, behaving as if the menu bar was in fact present.
Web Widget Commented Out
Web Widget Active
Example Code
import os
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtWebEngineWidgets import *
class WebPage(QWebEngineView):
def __init__(self, parent=None):
QWebEngineView.__init__(self)
self.current_url = ''
self.load(QUrl("https://facebook.com"))
self.loadFinished.connect(self._on_load_finished)
def _on_load_finished(self):
print("Url Loaded")
class MainWindow(QMainWindow):
def __init__(self, parent=None):
# Initialize the Main Window
super(MainWindow, self).__init__(parent)
self.create_menu()
self.add_web_widet()
self.show()
def create_menu(self):
''' Creates the Main Menu '''
self.main_menu = self.menuBar()
self.main_menu_actions = {}
self.file_menu = self.main_menu.addMenu("Example File Menu")
self.file_menu.addAction(QAction("Testing Testing", self))
def add_web_widet(self):
self.web_widget = WebPage(self)
self.setCentralWidget(self.web_widget)
if __name__ == "__main__":
app = QApplication(sys.argv)
main_window = MainWindow()
main_window.showMaximized()
sys.exit(app.exec_()) # only need one app, one running event loop
Development Environment
Windows 10, PyQt5, pyqt5-5.9
EDIT
The problem doesn't seem to be directly related to the menu bar. Even removing the menu bar the issue still occurs. That said, changing from showMaximized() to showFullScreen() does seem to solve the problem.
I no longer believe this is an issue with PyQt5 specifically but rather a problem with the graphics driver. Specifically, if you look at Atlassian's HipChat application it has a similar problem which is documented here:
https://jira.atlassian.com/browse/HCPUB-3177
Some individuals were able to solve the problem by running the application from the command prompt with the addendum "--disable-gpu" but that didn't work for my python application. On the other hand, rolling back the Intel(R) HD Graphics Driver did solve my problem. Version 21.20.16.4627 is the one that seems to be causing problems.
I'm new to Python (and programming in general) so forgive me if this is a dumb question.
I'm following a tutorial in a book for creating a GUI in Python. Right now I'm learning about how to make a Spin Control increment some static text. When I run it, the spin control shows up but the console says "value = event.GetPosition()
AttributeError: 'CommandEvent' object has no attribute 'GetPosition'"
The code is:
import wx
class Frame(wx.Frame):
def __init__(self, title):
wx.Frame.__init__(self, None,\
title=title, size=(300,250))
panel = wx.Panel(self)
sc = wx.SpinCtrl(panel, value='0', pos=(130, 50), size=(70, 25))
self.valueText = wx.StaticText(panel, label='', pos=(130,80))
sc.Bind(wx.EVT_SPINCTRL, self.spinControl)
def spinControl(self, event):
# Get spin control value
value = event.GetPosition()
# Update static text
self.valueText.SetLabel(str(value))
app = wx.App()
frame = Frame("wxPython Widgets!")
frame.Show()
app.MainLoop()
That code is literally copy/pasted from the book's website. I have wxPython installed and everything works perfectly up to that point.
Halp!
I've been working through that same book Python in a Day 2. I believe the content is already outdated.
If you change the line with GetPosition() to
value = event.GetEventObject().GetValue()
is correct. I can confirm that it works for Python 2.7.11.
Jeremiah
If you change the line with GetPosition() to
value = event.GetEventObject().GetValue()
it will work. The event just doesnt have the GetPosition attribute, so it cannot eb executed.
If you want to check which functions and attributes are available, you can use
print(dir(event))
This will show you everything which is available inside the event.
Michael
As the title says when I implement code to clear hinted text and it is run the application crashes.
As far as I know this is only on Mac OS X 10.8 but that is also all I have been able to run it on.
On other code it does run and only once I enter text into it (After giving focus) does it crash. But this app crashes immediately (I think something to do with no other widgets and so it get focus right away). Updated example so it no longer crashes right away now you have to click on the combo box and try to type in it for it to crash.
This however does not occur if the text is anything but "" it seems.
Code
import wx
class MyCrashyPanel(wx.Panel):
def __init__(self, parent):
wx.Panel.__init__(self, parent, -1)
# another widget to take focus at first otherwise it crashes instantly!
sizer = wx.BoxSizer(wx.VERTICAL)
self.text_ctrl = wx.TextCtrl(self, -1, value = "There are major problems here.\nWithout this to auto take focus this will crash immediatly just by trying to clear the hint.\nNow you have to click on the combo ctrl and try to type.", style = wx.TE_MULTILINE)
self.search_ctrl = wx.ComboBox(self, -1)
self.search_ctrl.SetMinSize((650, -1))
self.search_ctrl.SetSize((650, -1))
self.search_ctrl.SetHint("This is are hint text; once it is clear and you try to type something in it it will crash on Mac OS X")
sizer.Add(self.text_ctrl, flag = wx.EXPAND)
sizer.Add(self.search_ctrl)
self.SetSizer(sizer)
self.FirstTimeSearchGetsFocus = True
self.Bind(wx.EVT_BUTTON, lambda e: e.Skip(), self.text_ctrl)
self.search_ctrl.Bind(wx.EVT_SET_FOCUS, self.OnSearchFocus)
self.text_ctrl.SetFocus()
def OnSearchFocus(self, event):
print "Search Focus"
if 1==1:
print "First time"
# clear the hinted text
self.search_ctrl.SetHint("")
self.search_ctrl.Clear()
self.search_ctrl.Refresh()
self.FirstTimeSearchGetsFocus = False
event.Skip()
if __name__ == "__main__":
app = wx.App(False)
f = wx.Frame(None, -1)
MyCrashyPanel(f)
f.Show()
app.MainLoop()
Crash Report
[Too big get here http://pastebin.com/9B1Sgh3P ]
If it crashes, it's a bug in wxWidgets, so the only things to do are to:
Try with a later version, i.e. 2.9.5 or svn/git if you can build it yourself.
Report the bug if it still persists there, following the usual guidelines.
Background
I am about to resolve another issue, which consists in reserving screen-space for a Qt Window on X11. For this i use PyQt4 and Python-Xlib.
Situation
The application i want to save screen space for is a frameless Qt Window, 25px high and screen-wide, it's a panel in fact. The simplified code looks like this:
import sys
from PyQt4 import QtGui
from PyQt4 import QtCore
# this module i made myself (see below):
import myXwindow
class QtPanel(QtGui.QWidget):
def __init__(self, parent=None):
QtGui.QWidget.__init__(self, parent)
# here i explicitely name the window:
self.setWindowTitle('QtPanel')
self.resize(QtGui.QDesktopWidget().screenGeometry().width(), 25)
self.move(0,0)
self.setWindowFlags(QtCore.Qt.Widget |
QtCore.Qt.FramelessWindowHint |
QtCore.Qt.WindowStaysOnTopHint)
self.setAttribute(QtCore.Qt.WA_X11NetWmWindowTypeDock)
def main():
app = QtGui.QApplication(sys.argv)
panel = QtPanel()
panel.show()
xwindow = myXwindow.Window(str(panel.windowTitle()))
sys.exit(app.exec_())
if __name__ == '__main__':
main()
Now to reserve space for this QtPanel application, i need to call on xlib. Here below i will just show how i intend to 'grab' my window from X. The following module is imported in the code here above to get the Xwindow of my panel:
from Xlib.display import Display
from Xlib import X
class Window(object):
def __init__(self, title):
self._title = title
self._root = Display().screen().root
self._window = self.find_window()
def find_window(self):
my_window = None
display = Display()
windowIDs = self._root.get_full_property(
display.intern_atom('_NET_CLIENT_LIST'),
X.AnyPropertyType).value
print 'looking for windows:'
count = 0
for windowID in windowIDs:
count += 1
window = display.create_resource_object('window', windowID)
title = window.get_wm_name()
print 'window', count, ':', title
if self._title in title:
my_window = window
return my_window
Problem
Now when i run the QtPanel application, it should return a list of names of all the windows currently displayed by X. Despite having been named explicitly in the code (see here above) the QtPanel application either has no name (i.e. None or '') or is named 'x-nautilus-desktop', here is a sample of what was returned:
$ python ./Qtpanel.py
looking for windows:
window 1 : Bottom Expanded Edge Panel
window 2 : cairo-dock
window 3 : x-nautilus-desktop
window 4 : ReserveSpace - NetBeans IDE 6.9
window 5 : How to provide X11 with a wm_name for a Qt4 window? - Stack Overflow - Mozilla Firefox
Question
How can i 'name' my Qt Application or Qt toplevel window so it shows properly on X?
And/or: how can i identify my application in X other than with the application's name?
Although i don't quite know what the unnamed window is (and it seems related to launching the QtPanel application, the Xlib script is not able to find the window on display because it is queried before the event loop QApplication._exec(). A thread may be required to do that outside of the main loop.
In my application i have text control.
I want my text ctrl should be read only but when some one right click on this he is able to copy the value from that ctrl and he can paste that value in other text control.
If i made my text control read only with wx.TE_READONLY then copy/paste is not working.
Is there any requirement to handle other type of wx event or i have to set more type of wx style flags while creating the text control object.
Thanks in advance.
Hmm Im on windows 7 and don't have any problem copying from a textCtrl that has the wx.READ_ONLY style flag set.
You said you wanted to paste into another textCtrl -obviously you can't have the wx.READ_ONLY style flag set in the textCtrl you want to be able to paste into.
Try out the demo below, you should be able to copy from the textCtrl on the left(which is read only) to the one on the right(which doesn't have the read only style set).
import wx
class MainWindow(wx.Frame):
def __init__(self, parent, id=-1):
wx.Frame.__init__(self,parent,id, size=(200,200))
self.panel = wx.Panel(self,wx.ID_ANY)
bsizer = wx.BoxSizer()
read_only_txtCtrl = wx.TextCtrl(self,-1,
"This textCtrl is read only",
style=wx.TE_MULTILINE|wx.TE_READONLY)
editable_txtCtrl = wx.TextCtrl(self,-1,
"This textCtrl is editable",
style=wx.TE_MULTILINE)
bsizer.Add(read_only_txtCtrl, 1, wx.EXPAND)
bsizer.Add(editable_txtCtrl, 1, wx.EXPAND)
self.SetSizerAndFit(bsizer)
if __name__ == "__main__":
app = wx.PySimpleApp()
frame = MainWindow(None)
frame.SetSize((200,200))
frame.Show()
app.MainLoop()
We should bind wx.EVT_TEXT_COPY and wx.EVT_TEXT_PASTE with text control.
one can copy and paste data from text ctrl although text ctrl is read only mode.
Actually I had the same challenge. I needed a textbox where users could paste information (or open -> read file via a menu). The app would then analyze the info for correctness. But I didn't want to allow editing in the textbox - it would suggest that you could correct in the same textbox, while the app was for analysis only. Yeah, requirements, I know.
Weird thing was, I could make a readonly TextCtrl under MacOSX that would allow pasting (but not editing), but not on Windows.
In order to support both, I ended up creating a read/writesuper(MyWin, self).init(None, size=(800,600)) textbox (to allow pasting under windows) and binding wx.EVT_TEXT events to it (apart from wx.EVT_TEXT_PASTE for the obvious pasting). The EVT_TEXT handler that's triggered when the textctrl's contents change, simply shows a dialog that you aren't allowed to do this.
In the app a boolean this.painted plays the following role: when this.painted is true, then modifications of the textctrl aren't allowed. So, the onpaste handler first sets this.painted to false, then modifies the TextCtrl's contents, then sets this.painted to true (otherwise the dialog alert would also go off during the paste event, which I wanted to allow). Unfortunately when the EVT_TEXT handler goes off, the window's contents have already been modified by a user hitting some key. Therefore the app also needs a backup buffer to put back into the TextCtrl when such editing has been detected.
According to the Python docs, TextCtrl.ChangeValue() instead of SetValue() should not trigger the EVT_TEXT event (which would be handy) but I couldn't get that to work, might be my mistake due to not-enough-time-to-investigate-because-it-should-have-been-done-yesterday.
Not an elegant solution, but works.
import wx
class MyWin(wx.Frame):
def __init__(self):
super(MyWin, self).__init__(None, size=(800,600))
self.painted = True
self.backup = ''
self.text = wx.TextCtrl(self, style=wx.TE_MULTILINE | wx.HSCROLL)
self.text.Bind(wx.EVT_TEXT_PASTE, self.onpaste)
self.text.Bind(wx.EVT_TEXT, self.ontextchange)
self.Show()
def onpaste(self, event):
if not wx.TheClipboard.IsOpened():
buf = wx.TextDataObject()
wx.TheClipboard.Open()
success = wx.TheClipboard.GetData(buf)
wx.TheClipboard.Close()
if success:
self.painted = False
self.backup = buf.GetText()
self.text.SetValue(self.backup)
self.painted = True
def ontextchange(self, event):
if self.painted:
dlg = wx.MessageDialog(self, 'Editing not allowed', '', wx.OK)
dlg.ShowModal()
dlg.Destroy()
self.painted = False
self.text.SetValue(self.backup)
self.painted = True
app = wx.App()
frame = MyWin()
app.MainLoop()