Turn off PyQt Event Loop While Editing Table

12,903

Solution 1

blockSignals(bool) is intended for suppressing QObjects and their subclasses from emitting signals, thus preventing any other objects from receiving them in slots. But this is a QObject method. If you are specifically trying to prevent one object from emitting signals in response to changes that you are making, which might trigger calculations or some other expensive processing in a slot, then this is what you want.

But if your situation is that making repeated changes is causing expensive paint operations over and over (or other expensive events being generated on the widget), then you have the ability to disable updates with updatesEnabled(bool). A benefit of this method is that it recursively disables the children of the target widget, preventing them from being updated as well. So nothing in the hierarchy will receive updates until you enable again.

mainWidget.setUpdatesEnabled(False)
# do a bunch of operations that would trigger expensive events
# like repaints
mainWidget.setUpdatesEnabled(True)

Ultimately it depends on whether the source of your problem comes from triggering signals, or triggering widget events. Blocking the signals will still allow the widget to process its events, but just not notify any other listeners about it. updatesEnabled is a common way to wrap a number of list/table/tree updates. When it is enabled again afterwards, a single post update will be performed.

Solution 2

Signals can be temporarily blocked for any object that inherits QObject:

self.tableWidget.blockSignals(True)
# perform updates, etc
self.tableWidget.blockSignals(False)
Share:
12,903
flutefreak7
Author by

flutefreak7

I'm an Aerospace Engineer working for NASA doing solid rocket motor ballistics analysis. While software development is not in my job title, I love programming and try to use it to make my job and the jobs of my team members easier by developing analysis tools. My programming experience began like many Engineers with Excel VBA and Matlab, which expanded to Python and VB.Net. My job also requires I use a number of legacy FORTRAN analysis codes. I also program my TI-89, mod my phone/router, and make advanced spreadsheets documenting... everything. Discussions abound extolling the advantages of Python over Matlab. I do continue developing in Matlab because it’s used by my coworkers and is great with data. These days (2017) almost everything new I do is in Python with Matlab and Excel reserved for 'customers' who need tools on those platforms. I found Python whilst seeking freedom from commercial tools. Python is extensively used and well supported in the science and engineering community with tools like Scipy, Numpy, Matplotlib, Pandas, Spyder, Mayavi, etc, and the ease with which libraries can be utilized make Python immediately useful. Python is also learnable, powerful, brilliantly designed, philosophy focused, and well supported by an internet-spanning community. My current Python projects utilize PyQt to develop frontends and data exploration tools for CLI analysis codes. I've also begun to replace VBA with VB.Net for developing advanced Excel Add-Ins (with help from Excel-DNA). After reading plenty of discussions and flame wars online about VB.Net vs. C#, I finally decided that VB.Net is exactly where I want to be despite the popularity of C# in computer science and internet arenas. VB actually has a really strong heritage in engineering circles and will serve me better for rapid application development, Excel Add-Ins, and has a chance of being maintainable by my coworkers, who have experience in VBA and VB6. I also prefer VB.Net's more human-readable syntax, it has a lower learning curve for me since I'm very proficient with VBA, and recent additions to the language give it list and dictionary literals that are almost Pythonic! While the more lax nature of the compiler might make some programmers cry a little (Option Explicit turned off, late-binding, undeclared variables, etc.), it sure speeds up development when I don't have time to write perfect software. Most engineering code is some ugly hacked together version of good enough, and VB.Net fits that so much better than C#. I'll do my elegant production code in Python and my Excel Hack-foo in VBA or VB.Net. Outside work I spend most of my time with my awesome wife, our two cats, and (after Oct 2017...) my son. I enjoy Star Trek (NASA's the closest thing I could find to Starfleet Academy), video games, programming, jazz, playing the flute (yes.... jazz flute!), working on the house, and being involved with the young adult group at my church.

Updated on June 05, 2022

Comments

  • flutefreak7
    flutefreak7 about 2 years

    I'm developing a GUI with PyQt. The GUI has a qListWidget, a qTableWidget, and a plot implemented with Mayavi. The list refers to shapes that are plotted (cylinders and cones for example). When a shape is selected in the list, I want the shape's properties to be loaded into the table (from a dictionary variable) and the shape to be highlighted in the plot. I've got the Mayavi plotting working fine. Also, if the table is edited, I need the shape to be re-plotted, to reflect the new property value (like for a cylinder, if the radius is changed).

    So, when a list item is selected -> update the table with the item's properties (from a dictionary variable), highlight the item on the plot

    When the table is edited -> update the dictionary variable and re-plot the item

    The Problem: when I select a list item and load data into the table, the qTableWidget ItemChanged signal fires every time a cell is updated, which triggers re-plotting the shape numerous times with incomplete data.

    Is there a typical means of disabling the GUI event loop while the table is being programmatically updated? (I have experience with Excel VBA, in that context setting Application.EnableEvents=False will prevent triggering a WorksheetChange event every time a cell is programmatically updated.) Should I have a "table update in progress" variable to prevent action from being taken while the table is being updated? Is there a way to update the Table Widget all at once instead of item by item? (I'll admit I'm intentionally avoiding Model-View framework for the moment, hence the qListWIdget and qTableWidget).

    Any suggestions?

    I'm a first time poster, but a long time user of StackOverflow, so I just want to say thanks in advance for being such an awesome community!

  • flutefreak7
    flutefreak7 over 11 years
    Thanks! Hadn't thought of just disabling the signal itself (Still getting used to signal-slot structure). Your response lead me to Google "pyqt disable signal" which lead to a relavant StackOverflow question: stackoverflow.com/questions/7323295/… which reveals the blockSignals() method. Using table.blockSignals(True) before updating the table and table.blockSignals(False) afterwards produces the desired effect!
  • abarnert
    abarnert over 11 years
    Yeah, blockSignals is actually better than stashing their handlers (and +1 to ekhumoro for suggesting it), unless you're writing very odd code (where you have objects in the system that aren't real QObjects, or where you want to use the same code in Qt3 and Qt4, or…). Apologies for not suggesting that first, and glad you managed to find it anyway.
  • flutefreak7
    flutefreak7 over 11 years
    Thanks for the additional information about updatesEnabled(). This will likely come in handy for other operations. The hierarchical nature is nice since I could disable a layout element or a whole tab without disabling the entire GUI.