I have a somewhat strange problem. I'm coding a multithreaded app and am using SIGNALS to communicate the QThread's data to the GUI class data. Without further ado, here is a simplified code.
class GUI(uiMainWindow.MainWindow):
def __init__(self, parent=None):
super etc
self.thread = Thread()
self.connect(self.thread, SIGNAL("changeStatus(QString)"), self.setStatus, Qt.QueuedConnection)
def setStatus(self, status):
self.statusBar.setText(status)
class Thread(QThread):
def __init__(self, parent=None, create=True):
super etc
self.create = create
def run(self):
if self.create:
create_data()
if not self.create:
upload_data()
def create_data(self):
self.emit(SIGNAL("changeStatus(QString)"), "Changing the statusbar text")
#rest of the code
def upload_data(self):
self.emit(SIGNAL("changeStatus(QString)"), "Changing the statusbar text")
Pretty basic, right? However, here's the problem: the self.emit works only in create_data function, but not in upload_data (or for that matter, in any other function; I tried putting it in __init__ as well). I tried putting print "I got the status" + status in the setStatus function. Again, it works in the create_data() function, but not in the upload_data() function.
The differences between the two functions are relatively minor, and as far as I can tell, nothing is interfering with the self.emit function - in fact, in both cases, self.emit is only 4-5 lines "away" from the function definition.
This is really puzzling to me. Any help? Thanks in advance!
EDIT: again, as far as I can tell, the only difference between the two functions is in the run() - the first one is called if create parameter is True, and the second one if it is False.
I was right in my post. The difference between Thread() and Thread(create=False) was crucial. I had to define a new method (one was self.thread = Thread() and the other self.diff_thread = Thread(create=False)) and connect to different slots to make it work.
Related
Some weeks ago I had to simplify a program drastically, because I couldn't find a solution for this probably simple problem.
Now I'm stuck at the same issue again and hope somebody can help me to fix it.
I'm using PyQt5 and started a QWidget out of my main class Class_One, from which I opened a second class Class_Two with the following lines.
def on_create_search(self):
self.search_form = Class_Two()
self.search_form.show()
In Class_Two I save changes to a JSON file, which should also effect a dictionary and a visible QTreeWidget from Class_One.
So what I want to do is, to execute a method in Class_One, triggered by Class_Two, just as it was called from the running instance of Class_One.
The called method should read in the JSON file and apply the changes to the data and the GUI of the running instance of Class_One.
Calling such a method from another instance of Class_One didn't help me out, because the changes have to be applied to my running class instance of Class_One.
Perhaps there is an even better way, so I'm open for any suggestions.
Use callback.
class Class_One:
def callback(self, arg1, arg2):
# code you want
def on_create_search(self):
self.search_form = Class_Two()
self.search_form.show(self.callback)
class Class_two:
def show(self, callback):
# original code
callback(arg1, arg2)
I've been working in python on a project where I have a GUI which I split up a bunch of the work between classes. I don't know a lot of the best practices for passing data around between classes, and I've frequently run into the issue, where I have to implement something, or change something for work, and I've resorted to making a lot of the classes objects of another class in order to give it the data I need.
Any ideas or suggests would be greatly appreciated on how to keep my classes independent for later modification and still pass the relevant data around without affecting interfaces too much?
As an example
class Window():
def __init__(self, parent=None):
self.parent = parent
def doStuff(self):
#do work here
class ParseMyWork(Window):
def __init__(self, parent=None):
self.parent=parent
I often find myself doing stuff like the above giving objects to class Window
or simply inheriting everything from them as in ParseMyWork
There must be better and cleaner ways of passing data around without making my classes utterly dependent on eachother, where one little change creates a cascade effect that forces me to make changes in a bunch of other classes.
Any answers to the question don't necessarily have to be in python, but it will be helpful if they are
If I'm understanding your question correctly, I would say that inheritance is not necessary in your case. Why not give ParseMyWork a function for dealing with a specific Window task?
class Window():
def __init__(self, parent=None):
self.parent = parent
def doStuff(self):
#do work here
class ParseMyWork():
def __init__(self, parent=None):
self.parent=parent`
def doWindowActivity(self, window):
window.doStuff
Then you can use the function like this
work_parser = ParseMyWork()
window = Window()
work_parser.doWindowActivity(window);
That way you can use your work_parse instance with any window instance.
Apologies in advance for my Python, it's been a while so if you see any rookie mistakes, do point them out.
Keep it simple.py:
def doStuff(window):
#do work here
return window
def parseStuff(stuff):
pass
really.py:
from simple import doStuff, parseStuff
def really_simple(window):
okay = doStuff(window)
return parseStuff(okay)
don't complicate the class:
from really import really_simple
really_simple(window)
imo: classes are overly complicated objects, and in a lot of cases more confusing than they need to be, plus they hold references and modify stuff, and can be difficult to decouple once they have been tied to other classes. if there isn't a clear reason why a class needs to be used, then it probably doesn't need to be used.
Classes are super powerful, so it's good you're getting started with em.
Discalimer: Haven't worked in python for a while now, so things might not be exact. The general idea still applies though.
Getting into your question now:
I would say the best way to achieve what you want is to create an instance of the first object where you will extract information from.
Now when creating a class, it's vital that you have attributes within them that you will want to be stored within it that you would like to retrieve once the class is instantiated.
For example, using your Window class example above, let's say that you have an attribute called resolution. It would look something like this:
class Window():
def __init__(self, parent = None):
self.parent = None
self.resolution = '40x80'
Now the resolution information associated with your Window class is forever part of any Window class instance. Now, the next step would be to create a get method for resolution. This should be done as follow:
class Window():
def __init__(self, parent = None):
self.parent = None
self.resolution = '40x80'
def getResoultion():
return self.resolution
Now, the reason we created this get method is because we can now set a variable to the information that is returned with it.
So let's say that you have everything associated with your Window class in its own file (let's say the file name is called Window.py). In a separate file (let's call it main.py), you can do the following:
import Window
windowInstance = Window()
windowResolution = windowInstance.getResolution()
If you print out the variable windowResolution, you should get that 40x80 printed out.
Now, as a side note, I do believe it is possible to get the information associated with an attribute with an instance of a class by simply doing something like
windowResolution = windowInstance.resolution
but that is bad practice in general. The reason, in a nutshell, is because you are now exposing attribute names of your class which you do not want to do because it makes it easy for a person outside of your code to learn the name where that information is held and change it. This can then lead to a myriad of other problems when it comes to making an overall program work. That is why it is best practice to use getters and setters. I already showed what getters are. Simply a get method for attributes. Setters, as you can probably assume, allow for one to set the information of an attribute to something else. Now you might say "Gabe, if we can create setter methods, what's the point of it if they just change it". My answer to that is to not give a setter method to all attributes. For attributes you don't mind for a person to change, give it a setter method, but for attributes you do not want any outside users to touch, simply don't create a setter method for it. Same goes with getter methods too. Users don't need to see all of the information of all attributes that makes your program work. Here's a better explanation: https://en.wikipedia.org/wiki/Mutator_method
Now, back to your example. Now let's say you have your ParseMyWork class in its own file like we did with your Window class, and let's say that ParseMyWork needs the resolution info from Window class. You can do the following :
import Window
import ParseMyWork
windowInstance = Window()
windowResolution = windowInstance.getResolution()
parseInstance = ParseMyWork(windowResolution)
This will only pass the window resolution information associated with your Window class. Hope this helps.
I am writing a class that has many functionalities(therefore methods), but I require this class to run inside a thread(class opens a subprocess). I want to use the common way of declaring thread based classes of,
class HiStackOverflow(threading.Thread):
# Somethings...
However, as I said, this class of mine has many pseudo-private, regular and static methods. And as I declare them, I want to avoid overriding some necessary threading.Thread method by mistake.
Well I can always check the directory of threading.Thread and see if there are any method names that overlap, however this seemed like a inappropriate way to handle this. It may be impractical as the method count increases.
My question is, is this kind of implementation feasible ? If not, how should I handle this ? Should I write some wrapper class as the Thread handler.
Thanks in advance.
If you're worried about namespace clashes between your class and threading.Thread, I would definitely suggest that you use composition rather than inheritance (or keep the two functionalities separate entirely). There shouldn't be significant overhead to just wrapping the couple threading methods that you need and then name clashes become a non-issue.
It also more cleanly will separate the functionality of your class from the functionality provided by threading. That's likely to be a win in the long run for understanding your code.
There isn't much benefit from inheriting from Thread. You could have a factory method that creates the thread or even have its __init__ do it.
import threading
import time
class MyClass:
def __init__(self):
self._thread = threading.Thread(target=self.run)
self._thread.start()
def run(self):
for i in range(5):
print('worker thread', i)
time.sleep(.5)
def join(self):
self._thread.join()
my_obj = MyClass()
for i in range(3):
print('main thread', i)
time.sleep(.5)
my_obj.join()
print('done')
There seem to be some ideas conflated in this phrase:
but I require this class to run inside a thread(class opens a subprocess)
Classes don't "run". You can start a new thread which executes some class method, or an instance method. That class doesn't have to inherit from Thread. It doesn't even need a reference to the running thread. You just start to execute some function in a new thread and you're done.
Subprocesses are unrelated to threads. You don't need one to do the other.
If you're worried about overriding something, check the documentation (https://docs.python.org/3/library/threading.html#thread-objects). Otherwise, if you want to keep the reference to the thread, you can always do:
class HiStackoverflow:
def run(self):
self.thread = Thread(target=self.entry_point)
self.thread.start()
def entry_point(self):
...
You'll have to forgive me, I am trying to teach myself OO but I have come across this problem with composition and 'has-a' relationships.
class Main(object):
def A(self):
print 'Hello'
def B(self):
self.feature = DoSomething()
class DoSomething(object):
def ModifyMain(self):
#Not sure what goes here... something like
Main.A()
def run():
M = Main()
M.B()
A real world example of the above simplification is a PySide application where Main is a MainWindow, and DoSomething is a dynamically created widget that is placed somewhere in the window. I would like DoSomething to be able to modify the status bar of the mainwindow, which is essentially calling (in Main) self.statusbar().
If there is a shortcut in PySide to do this, Tops!! please let me know! However, I'm actually after the more general Pythonic way to do this.
I think I'm close ... I just can't make it work...
Why don't you use a signal and slot instead? That's a more Qt and OOP way of doing this.
In your dynamically created widget class:
self.modifyMain = QtCore.Signal(str)
In your main class:
#QtCore.Slot(str)
def changeStatusbar(self, newmessage):
statusBar().showMessage(newmessage)
in you main class after creating your widget:
doSomething.modifyMain.connect(self.changeStatusbar)
And in you widget class, where you want to change the statusbar of main, you say:
modifyMain.emit("Hello")
None of this is tested as I don't have a PySide installation handy.
There are two problems with your code:
At no time do you call ModifyMain; and
Main.A() will result in an error, because A is an instance method, but you are calling it on a class.
You want something like:
class Main(object):
def A(self):
print 'Hello'
def B(self):
self.feature = DoSomething() # self.feature is an instance of DoSomething
self.feature.ModifyMain(self) # pass self to a method
class DoSomething(object):
def ModifyMain(self, main): # note that self is *this* object; main is the object passed in, which was self in the caller
#Note case - main, not Main
main.A()
def run():
M = Main()
M.B()
if __name__=="__main__": # this will be true if this script is run from the shell OR pasted into the interpreter
run()
Your names all flout the usual python conventions found in PEP8, which is a pretty good guide to python style. I have left them as they were in your code, but don't copy the style in this example - follow PEP8.
I have a multi-threaded application written in Python in which one thread "takes care" of the GUI, and the other is the worker thread. However, the worker thread has two main functions (or so to say two main jobs), and I need to tell the run function which job exactly to do.
So what I had in mind was to create a run function in the worker thread which will take one parameter (save for "self). The parameter will either be "create" or upload. Without further ado, here's the somewhat-code that I have so far:
GUI.py
class GUI(QMainWindow):
def __init__(self, parent=None):
super, etc
self.worker = worker.Worker()
def create(self):
self.worker.start()
def upload(self):
self.worker.start()
Worker.py
class Worker(QThread):
def __init__(self, parent=None):
super, etc
def run(self):
self.create_data() # OR self.upload_data(), depends
So the question is, how can I tell worker.start() which function I want it to perform? I realize one could directly use worker.run() method, but I was told by the "Rapid GUI development with PyQT" never to call worker.run() directly, and always to use worker.start().
The start method of QThread doesn't accept arguments. However, you've inherited QThread so you're free to customize it at will. So, to implement what you want, just pass arguments into the constructor of Worker.
Here's your code sample slightly modified to show this in action:
class Worker(QThread):
def __init__(self, do_create_data=True, parent=None):
super(QThread, self).__init__()
self.do_create_data = create_data
def run(self):
if self.create_data:
self.create_data()
else:
self.upload_data(), depends
Eli Bendersky's answer is correct, however the order of arguments appears wrong.
If you call the Worker class like this:
The argument order that worked for me:
def __init__(self, parent=None, do_create_data=True):
The order shown in Eli Bendersky's answer produced this error message for me:
TypeError: QThread(QObject parent=None): argument 1 has unexpected type 'str'
Not sure why, but I'm sure someone can help explain.