PySide2 multiple QPainters active in None:0 - python

I'm working on a code that has a QWidget inherented menu object containing QPushButton inherented button objects. I want to add sub-buttons to some of the buttons, that appear upon hovering on their parent button. The problem is that when I hover on the parent, I get the following error from my logger every time I move my mouse.
qt_message_handler: line: 0, func: None(), file: None
DEBUG: QPainter::begin: A paint device can only be painted by one painter at a time.
qt_message_handler: line: 0, func: None(), file: None
DEBUG: QPainter::translate: Painter not active
Unfortunately, that doesn't hand over a lot of leads.
Only the menu object makes use of the paintEvent() function (with only one QPainter), and update() is only called once in the code. The errors don't appear to come from in or around that code. Or any other particular function - I tested every function by printing something at the beginning and end and checked if the logs appeared in between, but that never happened.
I tried messing around with QPainter.begin() and end(), but that didn't go anywhere either.
PS: I would like to post a code snippet, but I can't seeing as there's no particular part of the code - and posting the entire thing wouldn't make much sense either.

Related

Get the corresponding TextView of a TextBuffer

I have the following problem, you may help me with:
There exists a GUI, that was created with Glade. The window contains multiple items of the type Gtk.TextView.
My intention is to change the background color of one of these items after clicking on it. Each item is connected with a signal, that is fired to change the color.
The change of the color works fine, because what i get over the widget argument is the expected Gtk.TextView.
The next step I do, is saving the name of the widget gained through get_name() into a label for later use, because as soon as I click on another item the last one should be reset to the former color. Unfortunately, when I want to get this (former) item - using get_object()-Method from Gtk.Builder and saved name as parameter - I get an object of type Gtk.TextBuffer. Now, there is the problem that TextBuffer has no modify_bg/base facility - and no option to change the color.
Is there any way to trace back a TextBuffer's TextView?
Thanks in advance!
Regards

wx.lib.EVT_COLOURSELECT interfering with wx.lib.FloatCanvas.EVT_MOUSEWHEEL

The Problem:
It seems like one event is disabling another event. Before calling event B, event A works just fine. After event B fires, event A no longer works. Both events are custom ones that people made for their wxPython libraries (FloatCanvas and ColourSelect). I'd like to trace the generated events to make sure that, after event B, event A is still being fired (but perhaps not triggering the handler code?)
The Details:
I have a wxPython app where I create a wx.Panel object with two child items - a plot and a legend. This top level panel handles the majority of the events.
The plot is a wx.Panel object with a single wx.lib.FloatCanvas.FloatCanvas canvas in it.
The legend is a wx.Panel with multiple wx.StaticText and wx.lib.colourselect.ColourSelect objects in it (I'm plotting discrete data points).
On the plot, I bind FloatCanvas.EVT_MOUSEWHEEL to my zoom in/out function. On the legend, I bind the wx.lib.colourselect.EVT_COLOURSELECT event to my update_colors function which then sends the event to the parent panel via wx.PostEvent(event).
The parent panel then receives EVT_COLOURSELECT from the child and executes code that changes the colors of my plots.
Source Code:
I haven't had time to write a small sample that demo's the problem, but you can see the problem by running the source code:
https://github.com/dougthor42/wafer_map
Run the wm_app.py file and then go through the following test steps.
Testing Steps:
Scroll/zoom in and out - works just fine
Change a plot color (fires EVT_COLOURSELECT). If you're testing with the source code you do this by clicking on a legend color box and choosing a new color.
Attempt to zoom in and out again. Doesn't work!
Verify that all other events (key down, click-and-drag, mouse move) all work.
Things I've Tried:
Obviously these didn't work or else I wouldn't be here :-P
Unbinding the mousewheel event and rebinding it when the top level panel receives the event from the child.
Completely disabling the handlers for EVT_COLOURSELECT in both the parent panel and the legend.
I thought that perhaps there was something going on in my handlers. Turns out, just
triggering EVT_COLOURSELECT causes the EVT_MOUSEWHEEL to stop working.
Changing FloatCanvas.EVT_MOUSEWHEEL to some other event, for example FloatCanvas.EVT_RIGHT_DOWN
This does actually work! I loose the 'speed' info from the mouse wheel, but right-clicking
before and after step 2 both work.
Seems to indicate that it's an issue with the mouse scroll event specifically.
Has anyone had a problem where events interfere with each other?
It turns out that there wasn't any interference with events - at least not the events that I mentioned.
After a ton of fiddling and attempts at making a bare-bones version that still demonstrated the problem (which I was unsuccessful at doing), I figured out the root cause. Sadly, I did not figure out a workaround.
The Problem:
My plot wx.Panel was binding wx.MOUSE_LEFT_DOWN. It seems that this was preventing the parent wx.Frame window from giving focus to the Panel that held the plot and the legend.
The Solution:
I removed the bind to wx.EVT_LEFT_DOWN and that seems to fix the underlying issue. However, this is still not the ideal case because it causes two other problems:
I can no longer use my left mouse button on the plot. Not a big deal, I guess, because I can always bind right-mouse.
A user must first left-click on the plot area to give it focus before the mouse scroll or any keyboard shortcuts will work. This doesn't necessarily stem from not binding wx.EVT_LEFT_DOWN, but rather (I believe), from something that Windows does. See Focus-follows-mouse in wxPython? for a bit more info.
Failed Workaround:
I tried a workaround: adding code that sends the wx.EVT_LEFT_DOWN event to the parent but either that still didn't work or I was doing it wrong. Here's the left-click event handler that I tried:
def left_click(self, event):
print("left click!")
parent = wx.GetTopLevelParent()
wx.PostEvent(self.parent, event)
So anyway, this question is kinda solved. Hopefully what I've got here helps someone else out.

How to hide a Widget when the program starts in PyQt?

I have some objects in a PyQt GUI that I wish to be hidden when the program runs until a button is pressed that shows them. So far all my attempts have failed, I have experimented with Signals/Slots but I can't seem to find a way of calling a function without an action (e.g. a button press). I would like to know if it is possible to call hide() on an object in this way, and if so, how.
To Close:
QtCore.QObject.connect(self.closeWidget, QtCore.SIGNAL(_fromUtf8("activated()")), widgetName.close)
To Show:
QtCore.QObject.connect(self.actionShow, QtCore.SIGNAL(_fromUtf8("activated()")), widgetName.show)
In other words, widgets inherit a close() and show() method.
See http://pyqt.sourceforge.net/Docs/PyQt4/qwidget.html
Also, some example code: http://www.saltycrane.com/blog/2007/06/more-pyqt-example-code/

wxpython SearchCtrl two events triggered

I am using a SearchCtrl with a dropdown menu and I'm having some trouble with the events. When I click the little arrow next to the search button, the EVT_SEARCHCTRL_SEARCH_BTN is triggered, which is not what I want. I only want the EVT_MENU_RANGE to be triggered after I clicked an item, and not also the EVT_SEARCHCTRL_SEARCH_BTN before i click it.
self.search_ctrl = wx.SearchCtrl(self.panel_1, -1,
style=wx.TE_PROCESS_ENTER)
self.search_menu = wx.Menu()
self.search_items = {"text1":"value1", "text2":"value2"}
for txt in self.search_items:
self.search_menu.Append(-1, txt)
self.search_ctrl.SetMenu(self.search_menu)
self.Bind(wx.EVT_SEARCHCTRL_SEARCH_BTN, self.search, self.search_ctrl)
self.Bind(wx.EVT_MENU_RANGE, self.onSearchMenu)
Although I should probably add id's to the menu bind, this isn't causing the problem. The code works as expected when I comment out the search button bind.
UPDATE
Apparently this isn't a problem, but a 'feature' of the searchctrl. I tried the wxpython demo and the menu also showed up if I just clicked the search button, and not the arrow. It is apparently one button, instead of the two i thought it was.
Is there a way to accomplish my original request? Do i have to manually modify a textctrl, or is there an other solution?
All the examples I've seen suggest you need to specify a range of IDs when you call your menu bind.
Maybe by default it binds to something unexpected... ?
Edit - In light of your update, it seems likely that you're going to need to make a custom control to me..

Qt - Temporarily disable all events or window functionality?

I have a Qt program with many buttons, user-interactable widgets, etc.
At one stage in the program, I would like all the widgets to temporarily 'stop working'; stop behaving to mouse clicks and instead pass the event on to one function.
(This is so the User can select a widget to perform meta operations. Part explanation here: Get variable name of Qt Widget (for use in Stylesheet)? )
The User would pick a widget (to do stuff with) by clicking it, and of course clicking a button must not cause the button's bound function to run.
What is the correct (most abstracted, sensible) method of doing this?
(which doesn't involve too much new code. ie; not subclassing every widget)
Is there anything in Qt designed for this?
So far, I am able to retrieve a list of all the widgets in the program (by calling
QObject.findChildren(QtGui.QWidget)
so the solution can incorporate this.
My current horrible ideas are;
Some how dealing with all the applications events all the time in one
function and not letting through the events when I need the
application to be dormant.
When I need dormancy, make a new transparent widget which recieves
mouse clicks and stretch it over the entire window. Take coordinates
of click and figure out the widget underneath.
Somehow create a new 'shell' instance of the window.
THANKS!
(Sorry for the terrible write-up; in a slight rush)
python 2.7.2
PyQt4
Windows 7
You can intercept events send to specific widgets with QObject::installEventFilter.
graphite answered this one first so give credit where credit is due.
For an actual example in PySide, here's an example you might draw some useful code from:
my_app.py
from KeyPressEater import KeyPressEater
if __name__ == "__main__":
app = QApplication(sys.argv)
eater = KeyPressEater()
app.installEventFilter(eater)
KeyPressEater.py
class KeyPressEater(QObject):
# subclassing for eventFilter
def eventFilter(self, obj, event):
if self.ignore_input:
# swallow events
pass
else:
# bubble events
return QObject.eventFilter(self,obj,event)

Categories

Resources