Initialize instance variables outside of Python class - python

Edit
In comments inheritance was suggested however this is already being done and I've added additional code snippet to show.
There are a few similar questions of initializing instance variables outside of __init__ where instance variables are initialized further down in the class within another def function (method). This question isn't a duplicate of those questions.
I have three classes all declaring the same self.xxxx instance variables after the def __init__:
class AskQuestion(simpledialog.Dialog):
""" Prepends "\n" to text passed.
Appends "\n\nAre you sure?\n" to text passed.
Allows text to be highlighted and copied to clipboard with CTRL+C.
Blocks other windows from getting focus
MON_FONTSIZE is temporary font size until configuration file set up.
"""
def __init__(self, parent, title=None, text=None, confirm='yes',
align='center', thread=None, icon='warning'):
self.confirm = confirm # Append "Are you sure?" line?
self.align = align # data (text lines) alignment
self.thread = thread # The thread run before button click
self.loop_no = 1 # Loop counter (not used yet)
self.data = text # data (text lines) for text box
self.text = None # Textbox widget
self.icon = icon # Warning, Error, Info, Question icons
try:
self.font = (None, MON_FONTSIZE)
except NameError:
self.font = (None, 10)
# Shared functions
self.wait_window = wait_window_func
#self.body = body(self, parent)
#self.body = body
simpledialog.Dialog.__init__(self, parent, title=title)
How can these lines of code be spun out into a global function which is called to initialize the variables? I'm searching for a technique similar to the bash . (source command) or the C #include command except variables won't be sourced from another file, simply a global function within the current file (module).
FYI I'm looking for consistency and code reduction for tkinter simpledialog class wrappers for ShowInfo, AskQuestion, AskString, etc.

in a a case where your classes share init methods you can reduce code by inherting them, like this
class A(B):
where B is a parent class, also according to the question you can inherit more than one classes,like this
class A(B,C):
I am providing a generic answer to avoid the same discussion as in comments

Related

Python Tkinter Avoid using "root" name in lower level function

Inspired by this 300+ vote closed Q&A: Best way to structure a tkinter application?, I'm looking to avoid explicitly using root in a function within a class. I think it should be implicitly declared through self or parent or something like that. Here is the code in question:
I have this code...
self.label_this = tk.StringVar()
self.label_last = tk.StringVar()
self.label_total = tk.StringVar()
tk.Label(count_frame, textvariable=self.label_this, \
font=(None, MON_FONTSIZE)).pack(anchor=tk.W)
tk.Label(count_frame, textvariable=self.label_last, \
font=(None, MON_FONTSIZE)).pack(anchor=tk.W)
tk.Label(count_frame, textvariable=self.label_total, \
font=(None, MON_FONTSIZE)).pack(anchor=tk.W)
self.update_cnt_labels()
Then later on...
''' Get list of Window ID's on monitor now '''
new_windows = self.windows_on_monitor(new_windows)
new_windows_cnt = len(new_windows) / WIN_CNT
if self.old_windows_cnt == new_windows_cnt :
FlashMessage (self.label_this, "No new windows to remove...", \
3, 750, 250)
self.update_cnt_labels()
return
Then later on...
class FlashMessage:
def __init__(self, widget, message, count=5, on=500, off=300):
self.delay_show (1, widget, message)
for i in range(count):
self.delay_show (on, widget, "")
self.delay_show (off, widget, message)
def delay_show(self, ms, widget, message):
root.after(ms, widget.set(message))
root.update_idletasks()
I want to avoid using root in the last two lines and use self or something similar.
My program call chain is something like:
the traditional: root = tk.Tk()
bunch of mainline initialization stuff.
the class: ResizingCanvas(mycanvas)
mainline function: popup(event) which is bound to <ButtonPress-1>
Dynamically formatted menu.tk_popup(event.x_root, event.y_root)
the class: RemoveNewWindows()
the function: remove()
the class: FlashMessage() (show above)
the function: self.delay_show() (shown above)
Each class and function has haphazard self, positional parameters, *args and **kwargs which mostly serve no purpose. Indeed even the __init__ above might be unnecessary. This is a result of copying code all over stack overflow.
Every second word in the program seems to be self but the word parent is only used in the class ResizingCanvas(). Do I have to propagate parent down the call list and use it somehow?
You can call after and update_idletasks on any widget. There are many such functions that can be called on any widget but which have a global effect.
In your case, you'll need to pass some widget into the FlashMessage constructor and save the reference. You can then use the reference to call the functions.
You're passing something called widget that doesn't actually contain a widget. You need to rename it to something more appropriate (eg: var), and then pass in an actual widget.
(Note: you also are calling after incorrectly, which I've fixed in the following example)
For example:
class FlashMessage:
def __init__(self, widget, var, message, count=5, on=500, off=300):
self.widget = widget
...
def delay_show(self, ...):
self.widget.after(ms, var.set, message)
self.widget.update_idletasks()
Then, whenever you create an instance of FlashMessage you need to add a widget as the first parameter.
For example, assuming that count_frame is defined in the context where you create an instance of FlashMessage and it is an actual widget, it might look something like this:
if self.old_windows_cnt == new_windows_cnt :
FlashMessage (count_frame, self.label_this, "No new windows to remove...", \
3, 750, 250)
self.update_cnt_labels()
return

Appending dynamically created names to a class variable from UI Class [duplicate]

This question already has answers here:
pyside connection Error "RuntimeError: Failed to connect signal clicked()"
(2 answers)
Closed 4 years ago.
I am fairly new to the concepts of OOP. I am having a hard time even wording my question. Maybe the question has been answered already, but worded differently!
I have a class called Create_Capsules(). It has two functions:
create a cube
create a sphere.
I created a class variable that appends the names of these newly created capsules.
Create Capsule Class (psuedo-code):
class Create_Capsule(object):
def __init__(self):
super(Create_Capsule, self).__init__()
self.user_capsules = []
def cube(self):
#psuedo-code
cap_name = create_cube(name='capsule_cube01')
self.user_capsules.append(cap_name)
return cap_name
def sphere(self):
#psuedo-code
cap_name = create_sphere(name='capsule_sphere01')
self.user_capsules.append(cap_name)
return cap_name
I have another UI Class that has two simple QPushButtons, Cube and Sphere.
The functions Create_Capsules().cube() and Create_Capsules().sphere() are being called from these buttons.
At the end of this process, I want to be able to query the class variable to get a list of all capsules created.
I tried to create an object of the Create_capsule class in the UI and pass that to the functions when the cube/sphere buttons are clicked.
Excerpts from the UI code:
Class toolUI(obj):
addNewBboxLabel = QLabel("Add New Capsule:")
user_capsule = Create_Capsule()
addCubeButton = QPushButton("Cube")
addCubeButton.clicked.connect(self.addCubeClicked(user_capsule))
# addCubeButton.clicked.connect(functools.partial(self.addCubeClicked), user_capsule)
addSphereButton = QPushButton("Sphere")
addSphereButton.clicked.connect(self.addSphereClicked(user_capsule))
# addSphereButton.clicked.connect(functools.partial(self.addSphereClicked), user_capsule)
def addCubeClicked(self, capsule_obj):
"""
Adds a cube to the scene
"""
user_cube = capsule_obj.cube()
print(user_cube)
print(capsule_obj.user_capsules)
def addSphereClicked(self, capsule_obj):
"""
Adds a sphere to the scene
"""
user_sphere = capsule_obj.sphere()
print(user_sphere)
print(capsule_obj.user_capsules)
On executing this, on opening the UI, a cube is being created (even without clicking the cube button in UI). And, I get this error message:
addCubeButton.clicked.connect(self.addCubeClicked(user_capsule))
RuntimeError: Failed to connect signal clicked()
I can choose to not bother about the class variable approach, and instead return the name of the capsule from the addCubeClicked() and addSphereClicked() functions, collect them in the UI and append a list there. But, that feels dirty as I don't want to clutter up my UI function with any other logic.
I feel like I am missing a key concept of OOP here.
In your toolUI class, you should wrap your code inside a method, such as __init__. You may also want to add self. to your widgets.
class toolUI(obj):
def __init__(self):
self.addNewBboxLabel = QLabel("Add New Capsule:")
self.user_capsule = Create_Capsule()
self.addCubeButton = QPushButton("Cube")
self.addCubeButton.clicked.connect(self.addCubeClicked(self.user_capsule))
self.addSphereButton = QPushButton("Sphere")
self.addSphereButton.clicked.connect(self.addSphereClicked(self.user_capsule))
Part of the reason was that your code didn't exist with an unique instance of the class, and self was not a defined variable. Placing it inside a method with a self param will define that variable for use and also allow other methods to access properties belonging to that object (e.g. self.addCubeButton).

Creating and colorizing new constructs on a existing Scintilla lexer

All,
I'm using QScintilla to syntax-highlight my domain specific language (DSL).
Since my DSL is based on python, I use the existing Python Lexer for QScintilla.
I manage to create new keywords as following:
self.text = Qscintilla(self)
pythonLexer = QsciLexerPython(self.text)
self.text.setLexer(pythonLexer)
self.text.SendScintilla(QsciScintilla.SCI_SETKEYWORDS,1,bytes('WARNING', 'utf-8'))
Now, how do I choose a color to highlight my newly created keywords?
Thanks a lot!
The QsciLexerPython is quite limited when it comes to highlighting sets of keywords, as it only gives you two to play with. This limitation is imposed by the Python Lexer class from the underlying Scintilla library, so there's not much that can be done about it (unless you want to create a patch).
However, if you only need to highlight one extra set of keywords, then you can subclass QsciLexerPython and reimplement its keywords method:
class CustomLexer(QsciLexerPython):
def keywords(self, keyset):
if keyset == QsciLexerPython.HighlightedIdentifier:
return b'WARNING'
return QsciLexerPython.keywords(self, keyset)
With that in place, you can then set the color, font, etc for the style:
pythonLexer = CustomLexer(self.text)
pythonLexer.setColor(
QColor('purple'), QsciLexerPython.HighlightedIdentifier)
...
(PS: note that keywords can only contain single-byte characters in the range 0-255)
To gain even more flexibility, you can consider to build your own custom lexer, not derived from the existing QsciLexerPython one. Watch out - it will be more work.
QScintilla provides the QsciLexerCustom class for this purpose. You have to subclass it like this:
class MyLexer(QsciLexerCustom):
def __init__(self, parent):
super(MyLexer, self).__init__(parent)
[...]
''''''
def language(self):
[...]
''''''
def description(self, style):
[...]
''''''
def styleText(self, start, end):
# Called everytime the editors text has changed
[...]
''''''
'''--- end class ---'''
Please notice the following parts:
__init__(self, parent) : The constructor is typically where you create style-objects.
language(self) : This method must return the name of the language. You have to implement it, but what it actually gets used for is unclear to me.
description(self, style_nr) : Returns the descriptive name for a given style.
styleText(self, start, end) : Gets called everytime editors text has changed. Here you implement syntax highlighting!
For more details, you can visit the following website: https://qscintilla.com/subclass-qscilexercustom/

Can someone please explain how the second version of this code works?

I'm a beginner at Python and I'm currently on chapter 10/12 in my book 'Python Programming for the absolute beginner'. I understand OOP in Python but due to one chapter (which discusses some relevant information about OOP) being based around a program for playing 'Cards' I had to skip part of the chapter (because I don't know how to play Cards) and so I missed out on important information which I should know at this point in the book. The reason I'm saying this is because I will need a simple answer to my question because complex answers may be too difficult for me to interpret.
But anyway here is my problem, there is a piece of a code in my book which creates a simple GUI program (which I completely understand) and then there's an Object Oriented version of the program which I do not understand (main parts highlighted in '##'s). It contains something called a 'Superclass constructor' which completely confused me (I tried doing some research on it, but it just didn't make sense to me). If anyone can help explain to me how the second version of the code works (or give helpful resources) then I will be highly grateful:
First version of the code:
from tkinter import *
# create a root window
root = Tk()
root.title("Lazy Buttons")
root.geometry("200x85")
app = Frame(root)
app.grid()
bttn1 = Button(app, text = "This is a button")
bttn1.grid()
root.mainloop()
Second version:
from tkinter import *
class Application(Frame):
def __init__(self, master): # Why is 'master' called?
super(Application, self).__init__(master) # ?
self.grid()
self.create_widgets()
def create_widgets(self):
self.bttn1 = Button(self, text = "This is a button")
self.bttn1.grid()
root = Tk()
root.title("Lazy Buttons 2")
root.geometry("200x85")
app = Application(root)
root.mainloop()
Don't skip parts of a tutorial because you don't know the problem domain - you don't need to know how to play cards to understand how card game code relates to what the program does. To your actual problem:
class Application(**Frame**):
This creates a class Application that inherits from a class Frame. If you don't know inheritance, the tutorial you're following should explain it, or you could try this introduction to classes and inheritance that I just googled up.
**def __init__(self, master):
This creates a method, with the name __init__. This is a special method in Python, which behaves similarly to a constructor in other languages - essentially, whenever an Application is created, Python will immediately call its __init__ method before it gives the new object back to whoever made it. master is just an argument, same as any other to any other function.
super(Application, self).__init__(master)
This calls the constructor of the superclass, to let it initialise the new object. super(Application, self) figures out what the superclass is (in this case it is Frame; in more complex cases that you will come to eventually, this is harder to work out and super's magic becomes important).
self.create_widgets()**
This calls the method create_widgets, which you define below this. The object before the . gets passed into the method as the first argument, self - so, this calls a different method on the same object that the method you're in has been called on.
app = Application(root)
This creates an Application - objects are created by calling the class, like how list() creates a list. The argument you pass in gets handed to __init__ as its second argument (the new Application that Python creates behind the scenes gets passed as the first argument, self, as above). Python creates a new Application, calls its __init__ for you, and then assigns the new object to the name 'app'.
'super' part here is only to properly call constructor of base class (the class you are inheriting from.)
Let's consider following example:
class Device(): # class representing some drawing device
...
def fill(self, color)
... # actual code for draw on this device
screen = Device()
WHITE_COLOR = (255, 255, 255)
class Window(object):
def __init__(self, width, height):
self.width = width
self.height = height
def area(self):
return self.width * self.height
class ColoredWindow(Window):
def __init__(width, height, color):
super(ColoredWindow, self).__init__(width, height)
self.color = color
def fill(self):
screen.fill(self.width, self.height, self.color)
my_window = ColoredWindow(640, 480, WHITE_COLOR)
my_window.fill()
The first class here, Window, is a generic window that has width and height attributes that are passed in constructor.
ColoredWindow is a subscass of Window, it has additional attribute color.
When ColoredWindow is constructed, it needs somehow pass width and height parameters to its baseclass Window.
This is exactly what construction super(ColoredWindow, self).__init__(width, height) is for. The first part, super(ColoredWindow, self), returns a reference to baseclass (Window in our case), and second part, __init__(width, height), just calls its constructor with right parameters.
In your example master is not called, it's just parameter to __init__ method of Application class.

Problem with Classes in Python

Ok guys, I'm really new at python (and programming itself) so sorry for my ignorance, but I really needed to ask this.
So im doing a wxPython project where I added several tabs for a notebook (each tab of the notebook = a class) and there is one tab where I added a checkbox (in a tab, lets call it for example Tab1), and what I want is that when someone checks it, a button that exists in other tab (class called for example tab2) gets hidden where previously it was being shown.
Well I see that it isn't hard to accomplish this, but my problem is the classes (tab1 and tab2, in this example). I've been trying to figure it out by searching but I guess im not searching hard enough because I just can't get it right. If they were in the same class I wouldn't have a problem, but as they are in different classes, im having a huge struggle with this.
Hope someone can help me, and sorry for my ignorance once again.
EDIT: Sorry guys wasn't being shown/hidden, but rather being enabled/disabled.
class Tab2(wx.Panel):
def __init__(self, parent):
.....
self.jaddbutton = wx.Button(self,-1, label ="Button", size = (160,24))
self.jaddbutton.Bind(wx.EVT_BUTTON, self.jaddbuttonclick, self.jaddbutton)
def jaddbuttonclick(self, event):
....
class Tab1(wx.Panel):
def __init__(self, parent):
self.jdcheck = wx.CheckBox(self, -1, 'Disable')
self.jdcheck.Bind(wx.EVT_CHECKBOX, self.checkoptions, self.jdcheck)
def checkoptions(self,event):
checkboxval = self.jdcheck.GetValue()
if checkboxval == False:
self.jaddbutton.Disable() # This is what I want to do but it is on the other class
else:
self.jaddbutton.Enable() # Same as above
class TextFrame(wx.Frame):
def __init__(self):
p = wx.Panel(self)
self.nb = wx.Notebook(p, size = (750, 332))
#Tabs
tab1 = Tab1(self.nb)
tab2 = Tab2(self.nb)
self.nb.AddPage(tab1, "ssomething")
self.nb.AddPage(tab2, "somethingr")
This sounds more like a wxpython question than a classes question. Normally, in python, tab1 would need a handle to tab2 in order to hide the button in tab2. Or it would need a handle to some shared resource, like a parent class or shared model class, that would allow tab1 to affect settings in tab2 (like the hiding of a button). PyQt provides an event system to allow communication between classes which may not necessarily contain handles to each other. What is the common "accepted" way to communicate in wxpython?
Here is a fairly abstract example of the shared parent solution.
class Parent(object):
def create_tabs():
self.tab1 = Tab1(self)
self.tab2 = Tab2(self)
def hide_tab2_button():
self.tab2.hide_button()
class Tab1(object):
def __init__(self, parent):
self.parent = parent
def on_checkbox_checked(self):
self.parent.hide_tab2_button()
class Tab2(object):
def __init__(self, parent):
self.parent = parent
def hide_button(self):
self.button.hide() # Or whatever the wxpython command is to hide a button.
In the tabs' __init__, save the parent reference (the notebook):
class Tab1(wx.Panel):
def __init__(self, parent):
self.parent = parent
...etc, etc...
Then, self.parent.GetPage(x) lets you access the x-th page (i.e., tab) of the notebook from any other page (tab). So instead of self.jaddbutton.Disable() etc, you'd be using, e.g.:
othertab = self.parent.GetPage(1)
othertab.jaddbutton.Disable()
and so forth.

Categories