I'm new to Python and PyQt. What is the best way to keep 4 QtTreeWidgets synchronized so that the items are the same as well as all the attributes of all the items? These widgets appear in different dialog boxes at different times during a session. For a number of reasons, I need to keep as much of the existing code, signals and layout as intact as possible. The Model/View division would be the obvious first place to go, but I don't want to touch any of the methods that are used to access or update the tree. I'm planning to refactor the whole thing in a few months, but I need something quickly to carry me until then.
Since each QTreeWidget is a convenience class, each has its own data. The UI is maintained in Qt Designer and I don't want to keep it that way.
When each dialog is initialized, the tree appears. The application has a singleton class that all dialogs can use to reference its variables/attributes.
In the initialization of each parent dialog, couldn't I check to see if a 'locationTree' attribute exists in the singleton. If not, I would need to populate it with its initial state and have the tree in the dialog use it or a copy of it. Any time the state of the dialog tree is altered in ways that I can trap, I'd like to update the singleton 'locationTree' to mirror the change. Although there's a clone method on a QTreeWidgetItem, I didn't see a corresponding method for the entire QTreeWidget.
How can I accomplish this with the least amount of change to the existing code base and GUI layout?
John
Yes using the MVC facilities is the way to go ...
Even though you are using QTreeWidget you are still working with a class derived from QAbstractItemView therefore the model() and setModel() calls are available. Take a model from one of the widgets that you are creating and then set it in the other widgets. Whenever you change the data in one of the widgets the other widgets will follow suit as they are using the same instance of model.
If you need to maintain the same selection state in all for widgets (which parts of the tree are open or close) that might be a little bit harder but it might actually work by using the same selectionModel selectionModel() and setSelectionModel()
I'm sure you're right that using Model/View is the best approach.
But without an idea of roughly how many items your tree widgets will have, and how frequently they'll be updated, it's hard to weigh up alternative approaches. Also, what version of Qt are you using?
If the number of updates and items are not huge, one approach is to introduce a class that inherits QObject (so it has signals and slots), and make it responsible for keeping all your QTreeWidgets in sync.
By connecting signals and slots for each QTreeWidget to a single other object, you avoid the nightmare of having every tree widget know about every other one.
Related
I have a GUI programmed in PyQt with many widgets and different windows, etc. The data for the GUI is stored in a python object. This object should be reachable from every widget in the program. Where should I put this object?
Right now I have it in the QMainWindow instance that is used for the program's main window. The problem is that it is hard to reach the QMainWindow object from deeply nested widgets. It seems much simpler to use the QApplication instance for that, because you can get it with QtCore.QCoreApplication.instance() (as shown in this answer). However, I couldn't find any other examples encouraging you to change the QApplication class, so I wonder if it really should be used that way.
What approach would you suggest?
The correct approach is to put this data/settings object in a separate module. This can then be simply imported wherever it is needed. Ideally, the module (and the code which creates the data/settings object) should be largely independent from the rest of the application.
There is no real value in tying the data/settings object to the application instance, since you would still have to import either QApplication or qApp to access it anyway. And the same thing applies to the QMainWindow - it just moves the problem to a different location, and adds an unnecessary layer of indirection. Another big problem with this approach is that the data/settings object cannot be accessed until an instance of the application or main window becomes available. Very often, the data/settings object will be required during the initialisation of various parts of the application, so tying it to specific GUI elements can easily lead to circular dependencies, or other ordering problems.
I suppose the key design principle here is Loose Coupling: once you've decoupled your data/settings object from the GUI, the rest of the application can access it wherever and whenever it is required.
I tried creating GUI with a few widgets, all of them without secifying a parent.
It worked fine.
Is this Ok, or there is reason to specify the parent?
Thanks!
In general, it's better to specify a parent wherever possible, because it can help avoid problems with object cleanup. This is most commonly seen when exiting the program, when the inherent randomness of the python garbage-collector can mean objects sometimes get deleted in the wrong order, causing the program to crash.
However, this find of problem does not usually affect the standard GUI widgets, because Qt will automatically reparent them once they have been added to a layout. The more problematic objects are things like item-models, item-delegates, graphics-scenes, etc, which are closely linked to a view.
Ideally, a pyqt program should have one root window, with all the other objects connected to it in a parent-child hierarchy. When the root is deleted/closed, Qt will recursively delete all its child objects as well. This should leave only the pyqt wrapper objects behind, which can be safely left to the python garbage-collector to clean up.
A more constructive benefit of specifying parents, is that it simply makes objects more accessible to one another. For instance, a common idiom is to iterate over a group of buttons via their parent:
for button in parent.findChildren(QAbstractButton):
print(button.text())
I have constructed a main window GUI using qt designer and pyqt. As the program grows more complex, using only one class may result in too many methods and attributes to manage. I figured that I should construct new classes in order to make things more manageable.
My first question is, how do I know when do I add a new class for my application? Is there any rule of thumb as a general guide? Is it a good idea to add a new class for new windows/tabs?
My second question is, if I added new classes for my application, how do my new class gain access to the Ui_MainWindow design file that I designed in Qt designer? Below is the sample code for my main window. Its a simple clock which displays the current time. Lets say if I would like to create a class for the clock display itself, how can I rewrite the code using OOP efficiently?
from PyQt4 import QtGui
from myMainWindowUI import Ui_MainWindow
class MyMainWindow(QtGui.QMainWindow, Ui_MainWindow):
def __init__(self, *args, **kwargs):
super(MyMainWindow, self).__init__(*args, **kwargs)
self.setupUi(self)
self.timer = QtCore.QTimer(self)
self.timer.timeout.connect(self.Time)
self.timer.timeout.connect(self.Date)
self.timer.start(1000)
self.lcdNumber_time.setDigitCount(8)
self.lcdNumber_time.display(strftime("%H"+":"+"%M"+":"+"%S"))
self.label_dynamic_date.setText(strftime("%Y"+" "+"%B"+" "+"%d"+", "+"%A"))
def Time(self):
self.lcdNumber_time.display(strftime("%H"+":"+"%M"+":"+"%S"))
def Date(self):
self.label_dynamic_date.setText(strftime("%Y"+" "+"%B"+" "+"%d"+", "+"%A"))
app = QtGui.QApplication(sys.argv) # A new instance of QApplication
form = MyMainWindow()
form.show()
app.exec_()
In general, this isn't necessarily a Qt-specific problem. It isn't necessarily a python-specific problem either. You could extend this question to any language that supports class-based programming, or even any language with functions.
It makes sense to write a class when you want to encapsulate behavior. A class should usually provide a single purpose, and expose an interface to the outside that allows users of the class to interact with exactly the behavior you have designed. Once you have this single-purpose class, you now have reusable behavior. You could apply part of this reasoning to functions, where you say a given function has a specific purpose and once you design it to do the one bit of behavior, you now have a reusable function.
Applying this to Qt, it would make sense to move code into its own class when its logic is no longer trivial. An example would be where you are first creating and showing a QMessageBox from your main window. But then at some point you need to collect more types of information, and even pass some initial information in when you construct the dialog. While you could construct this on the fly in your main window, as needed, it would be better to move it into its own dialog class, with its own private logic of how to be constructed. Then you just instantiate one as needed, passing it the expected parameters to its constructor. Now your main window no longer has to also be concerned with constructing special dialogs.
Another point (which wasn't exactly clear from your question) is that Qt Designer UI files each represent a single class. It is expected that this UI definition will be applied to a single class in code. It would be bad design to have ClassA(UI_mainWindow) and ClassB, and have ClassB access members of ClassA or know anything about the internal implementation of ClassA. Back to our topic of "separation of concerns", ClassB should have its own purpose and interface, and be used by the ClassA(UI_mainWindow) to achieve that purpose. You don't want ClassB knowing anything about the main window or being able to do more than its designed purpose.
Let's assume your timer example was actually more trivial than you have shown it to be. If you moved it to another class, you should rely on custom signals to communicate intentions back to other classes like the main window. Or you could move each of the lcd and label widgets into their own custom classes with their own timer logic that made them self contained. Either way, signal/slot lets custom widgets connect with each other without needing to know anything about the other widgets.
In summary, you could say that it would be good to create individual classes in Qt when you are constructing any non-trivial UI elements in another class (when it requires many lines of code, or it requires a bunch of SLOT functions and wiring for internal logic). This will keep you from repeating your logic, and allow you to have reusable code. It will also keep your main window smaller and easier to debug, since you can keep a smaller mental model in your brain of what the main window is doing. If you try to keep your UI elements as single-purpose focused and generic as possible, you will end up having a lot of classes that can be reused.
I'm programming python + Gtk3.
I have a Gtk.TreeView with a Gtk.ListStore as model.
At some point of the program I need to destroy the treeview in order to put a fresh one on it's place.
However I don't know what happens with the model. Should I destroy it, clear it, or just leve it there and let python to eat it?
I've also thinked in recycle the same model to the new treeview, but I'd prefer not: too much trouble...
Thanks!
You can leave it to Python's garbage collector, the same way it would go if you'd close the application (it will call g_object_unref on both).
That said, remember that the idea behind the separation of models and views, is that you can mix them the way you like, i.e. display the same model in different views or even alternatively displaying different models in the same view. That you need to replace both may indicate problems in the way you are designing your UI.
Im working on optimizing my design in terms of mvc, intent on simplifying the api of the view which is quite nested even though Iv built composite widgets(with there own events and/ pubsub messages) in an attempt to simpify things.
For example I have a main top level gui class a wxFrame which has a number of widgets including a notebook, the notebook contains a number of tabs some of which are notebooks that contain composite widgets. So to call the methods of one of these composite widgets from the controller I would have
self.gui.nb.sub_nb.composite_widget.method()
To create a suitable abstraction for the view I have created references to these widgets (whose methods need to be called in the controller) in the view like so
self.composite_widget = self.nb.sub_nb.composite_widget()
so that in the controller the call is now simplified to
self.gui.composite_widget.method()
Is this an acceptable way to create an abstraction layer for the gui?
Well that's definitely one way to handle the issue. I tend to use pubsub to call methods the old fashioned way though. Some people like pyDispatcher better than pubsub. The main problem with using multi-dot method calling is that it's hard to debug if you have to change a method name.