which one of the following is considered better a design and why ?.
i have 2 classes , one for the gui components and the other is for it's events.
please put in mind that the eventClass will be implemented so many times, (sometimes to get data from an oracle databases and sometimes mysql databases )
class MainWindow:
def __init__(self):
self.myEvents = eventClass() # the class that has all the events
self.button = button # consider it a button from any gui library
self.menu = menu # menu box
def bottonEvent(self):
data = self.myEvents.buttonEvent()
self.menu.populate(data)
class eventClass:
def __init__(self):
pass
def getData(self):
return data # return data to puplate in the list
OR
class MainWindow:
def __init__(self):
self.myEvents = eventClass(self) # the class that has all the events
self.button = button # consider it a button from any gui library
self.menu = menu # menu box
def bottonEvent(self):
self.myEvents.ButtonEvent()
class eventClass:
def __init__(self,window):
pass
def ButtonEvent(self):
window.menu.populateData()
please inform me if anything was unclear
please help ,
thanks in advance
The first choice is better "decoupled": the event class needs and has no knowledge whatsoever about the window object or its menu attribute -- an excellent approach that makes the event class especially easy to unit-test in isolation without any overhead. This is especially nice if many implementations of the same interface need to exist, as you mention they do in your case.
The second choice introduces a mutual dependency -- an event object can't work without a window object, and a window object builds an event object. That may be an acceptable complication in more abstruse cases where it buys you something, but for this specific use it sounds more like an arbitrary extra difficulty without any real plus.
So, I would recommend the first form.
Related
I have a question regarding Tkinter in Python.
I was thinking of the smartest/most commonly used way of creating GUIs with many/multiple Entries, Lables, Buttons, etc.
In my first sketches I just put them before the window.mainloop(), which at some point becomes confusing and unreadable. I then used methods for each Label, Button,... like this:
def someInput():
someInput = Entry(controlFrame)
someInput.grid(column = 1, row = 1)
...
Now I was thinking, if it makes sense to put them into a class like this:
class allInputs():
def inputOne(*args):
...
def inputTwo(*args):
...
What is your preferred way of doing this and why?
Thanks in advance.
My typical framework will look something like this
class App(tk.Frame):
def __init__(self,master=None,**kw):
tk.Frame.__init__(self,master=master,**kw)
self.btnOne = tk.Button(self,text="Hello")
self.btnOne.grid()
self.ow = OtherWidget(self)
class OtherWidget(tk.Frame):
....
if __name__ == '__main__':
root = tk.Tk()
App(root).grid()
root.mainloop()
The main application is a class (a sub-class of a tk Frame) and each "sub-component grouping" of widgets is its own class.
For example if I have a button which populates a text box, then they will be part of the same class. A textbox and it's scrollbar will be another class.
Basically I will group together widgets by their function and put them in the same class, all of which will be grouped in to the application class.
This makes sense to me as any data shared between widgets exist within the same class 'namespace' and they can access each others data without having to deal with globals.
I'm working on a coursework for my uni (GUI program) and I run into a problem as my code works but the specification is that we use OOP instead of just functions, and I'm lost.
I tried making new classes for each button but I don't know how to make them work like they do in the functions.
def add():
#get input
task=txt_input.get()
if task !="":
tasks.append(task)
#updating the list box
update_listbox()
else:
display["text"]=("Input a task.")
with open("ToDoList.txt", "a") as f:
f.write(task)
f.close()
txt_input=tk.Entry(root, width=25)
txt_input.pack(pady=15)
add=tk.Button(root, text="Add", fg="DarkOrchid3", bg="blanched almond", command=add)
add.pack(pady=5, ipadx=15)
This allows the user to add a task to his to-do list in the GUI, but like I said it should be using OOP not functions.
If I get to understand this one, I should be able to do the rest of the buttons.
UPDATE:
Ok so I tried the solution given below and I don't really know what is wrong with my code, the GUI appears but the adding functions won't work.
class ToDoList():
def __init__(self):
self.tasks = []
def update_listbox(self):
#calling clear function to clear the list to make sure tasks don't keep on adding up
clear()
for task in self.tasks:
box_tasks.insert("end", task)
def clear(self):
box_tasks.insert("end", task)
class adding():
def add(self):
task=txt_input.get()
if task!="":
self.tasks.append(task)
update_listbox()
else:
display["text"]=("Input a task")
It's not clear what your teacher meant about using classes. I'm going to guess that they want you to create a "todo list" object that has methods for adding and removing tasks. I don't know whether they want the GUI to be part of that class or not. It could be that your entire application is made of classes, or you could only use the class for the business logic.
I think you should start by creating a class just for the business logic. It would look something like this:
class ToDoList():
def __init__(self):
self.the_list = []
def add(self, value):
<code to add the value to self.the_list>
def remove(self, item):
<code to remove a value from self.the_list>
With that, you can write a simple little program without a GUI, which makes it easy to test the logic:
# create an instance of the to-do list
todo_list = ToDoList()
# add two items:
todo_list.add("mow the lawn")
todo_list.add("buy groceries")
# delete the first item:
todo_list.remove(0)
To build a GUI on top of that, you could either add the GUI component to the existing class, or create a new class specifically for the GUI. Each has pros and cons.
In the following example, the GUI is a separate class which uses the ToDoList class to maintain the data. This design lets you re-use the underlying todo list logic in tests, in a GUI, and even in a webapp or possibly even a mobile app.
class ToDoGUI():
def __init__(self):
# initalize the list
self.todo_list = ToDoList()
# initialize the GUI
<code to create the entry, button, and widget to show the list>
def add(self):
# this should be called by your button to the list
data = self.entry.get()
self.todo_list.add(data)
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 having difficulties in trying to get a function in a separate class. I have a main class with a few functions, one of which is reset:
class GUI(wx.Frame):
[GUI STUFF HERE]
def reset(self):
self.data = [0]
Within that class i also have before the subroutines to initiate another class:
self.controlPanel = controlPanel(self.panel)
Which initiates another class which is a staticbox with buttons. Within that class I have a function bound to a button event:
def reset(self, event):
GUI.reset()
where the function "reset" is in the main GUI class. I get an error when i try to call reset in the main class, yet I can do it the other way round. Why is this and how can I fix it? I want button events in child classes to call a function in the parent class.
Thanks in advance.
"GUI" is not defined in "controlPanel", you want to call the method of the instance of "GUI".
One way would be to do the following in your button handler:
self.GetParent().reset()
Depending how complex your application this might get out of hand as it will no longer work if you insert another layer in between GUI and controlPanel.
You might want to look into using 'wx.lib.pubsub' and in your controlPanel use 'pub.sendMessage' and in your GUI use 'pub.subscribe'.
wxPython Phoenix pubsub doc
pubsub's doc
My class MainWindow(QMainWindow) for PyQt4 GUI has grown now and I want to split it somehow. The problem is that all numerous functions handling signals are very interconnected and influence other functions of the class. Is there any way to split it into several classes / files? Maybe separating all signals into one class? I don't really understand how to do that technically... I've also heard that there is some restriction from Qt (or PyQt) for multiple inheritance, which could solve the problem I guess (again, not obvious for me how exactly).
Just as an idea how it looks now (very very simplified, of course):
calss MainWindow(QMainWindow):
...
def f1(self):
if self.a1 == '...':
...
def f2(self):
if self.a2 == '...':
...
def update(self):
self.f3()
self.f4()
self.lineEdit.setText(self.a3)
...
...
def on_radioButton_toggled(self):
if self.radioButton.isChecked():
self.a1 = '...'
def on_comboBox_currentIndexChanged(self):
if self.checkBox.isChecked():
self.a2 = '...'
self.f1()
else:
self.f2()
self.update()
...
In my application I did it like this, there's the main window which contains child widgets (frames and stuff...), the main window does basically two things: initialize its children and connect the signals between them. Like this you have a hierarchy of views which is much simpler to handle that one big thing.
I think there isn't a painless move from your program to a more hierarchical one, I could say: you should have though of that earlier, but I don't. =P
To design the main window and its children QTdesigner comes in very handy.
And yes, AFAIK a class should not inherit form more than one PyQt class.