Class of Widget Dependency Python TKinter - python

I am designing a gui using python Tkinter. I try to wrap my code in classes. I use different class for each frame. The code is more or less like this.
Class GetEntry():
"""This class will acquire the text in entry widget"""
Class Frame1():
"""Consist of all entry widget"""
Class Frame2():
"""Consist of all button widget"""
Class Main_App()
"""All classes are called here"""
However, I want to call GetEntry class when one of the button in class Frame2 is clicked to acquire the text in entry widget located in class Frame1. Any suggestion to do that?
Thanks in advance.

I Finally get it works. I simply instantiate the GetEntry command inside Frame2, and add attribute entry from Frame1 when calling Frame2. My code is as follows.
class CommadCallback():
def __init__(self, object)
self.object = object
def function(self):
self.object.get()
class Frame1():
#Entry instantiation
class Frame2():
def __init__(self, object):
self.object = object
self.function1()
def function1(self):
self.function = CommandCallback(self.object).function()
Class MainApp():
.....
self.frame1 = Frame1(self)
self.frame2 = Frame2(self, self.frame1.entry)

Related

Kivy how to use FileBrowser properly inside of a popup

I am looking for a way to create a popup box with a filebrowser inside of it by clicking a button from the main app screen. The below snippet is the class that is called when the upload button is clicked from the main app. It will render the popup with the file browser, but the on_* kwargs do not run the respective methods.
class UploadPopup:
def __init__(self, short_text='heading'):
browser = FileBrowser(select_string='Select', cancel_state='down')
browser.bind(on_success=self._fbrowser_success,
on_canceled=self._fbrowser_canceled,
on_submit=self._fbrowser_submit)
self.popup = Popup(
title=short_text,
content=browser, size_hint=(0.9, 0.9),
auto_dismiss=False
)
self.popup.open()
def _fbrowser_canceled(self, instance):
print('cancelled, Close self.')
self.popup.dismiss()
def _fbrowser_success(self, instance):
print(instance.selection)
self.popup.dismiss()
def _fbrowser_submit(self, instance):
print(instance.selection)
self.popup.open()
Any ideas??
Where ever you are calling UploadPopup(), you need to save a reference to it, so that it does not get garbage collected. For example, you might want to do self.pop = UploadPopup() in your main app.
Also, in your event handling methods, you probably want to replace self.popup.open() with self.popup.dismiss().
I have already accepted an answer, but would like to expand on that a bit. #john-anderson was correct in that garbage collection was collecting the instantiation. I was originally doing this...
class MainScreen(Screen):
...
#staticmethod
def upload(self):
this = UploadPopup()
...
class UploadPopup():
....
see original post
....
In order to resolve this issue I had to instantiate in the init method of my MainScreen class add an open method to the UpdatePopup class and call that method when the button was clicked.
class MainScreen(Screen):
def __init__(self):
self.upload_popup = UploadPopup()
...
#staticmethod
def upload(self):
self.upload_popup.start()
...
class UploadPopup:
def __init__(self, short_text='heading'):
browser = FileBrowser(select_string='Select', cancel_state='down')
browser.bind(on_success=self._fbrowser_success,
on_canceled=self._fbrowser_canceled,
on_submit=self._fbrowser_submit)
self.popup = Popup(
title=short_text,
content=browser, size_hint=(0.9, 0.9),
auto_dismiss=False
)
def start(self):
self.popup.open()
....

Cannot find methods about binding Qt-Designer4 with Python

I'm tired about looking for the methods to deal with widgets within python class (Python 2.7 & PyQt4) who load file.ui (GUI QTDesigner)
CODE
form_class = uic.loadUiType("MyPythonProgram.ui")[0]
class MyWindowClass(QtGui.QMainWindow, form_class):
def __init__(self, parent = None):
QtGui.QMainWindow.__init__(self, parent)
self.setupUi(self)
self.btn_buscar.clicked.connect(self.buscar)
def addingResultsToQListView(self):
for item in SomeList:
self.listView.addItem(item) ###It's not correct, but cannot find the right one
def onListItemClicked():
getItem = listView.currentItem().text() ###It's not correct, but cannot find the right one
def buscar(self):
getEditText = self.textEdit.toPlainText()
### Don't know how to do this function. I want to get the edittext to search on some website and retrieve the results into a list. then the list will be added to QlistView (just found C++ methods, not for python)
#Finally
getEditText = '' ###After click on 'btn_buscar', want to clear this field
app = QtGui.QApplication(sys.argv)
MyWindow = MyWindowClass(None)
MyWindow.show()
app.exec_()
It could be helper to get some DOC, or some help about making python apps hybrid (Android if its possible), keeping .ui and .py layers separately as I'm trying to show you.
This is my .ui for more information:
QUESTION'
How could I bind python functions with elements on .ui? I was trying too much methods but didn't find the right one. Need to know how to deal with QlistView and Qedittext... Thanks
This is the way I do it: separate the classes between construction (loading) of the UI and changing its content.
form_class = uic.loadUiType("MyPythonProgram.ui")[0]
class MyWindowClass(QtGui.QMainWindow, form_class):
def __init__(self, parent = None):
QtGui.QMainWindow.__init__(self, parent)
self.setupUi(self)
class myGui:
def __init__(self):
self.gui = MyWindowClass() # that's the trick!
# self.addindResultsToQListView() # doesn't work, because I don't have your list items
self.gui.btn_buscar.clicked.connect(self.buscar)
self.editText = None
def show(self):
self.gui.show()
def addingResultsToQListView(self):
for item in SomeList: # you need to specify this `list` before this works!
self.gui.listView.addItems(item)
def buscar(self):
self.editText = self.gui.textEdit.text()
self.gui.textEdit.setText("")
app = QtGui.QApplication(sys.argv)
MyWindow = MyGui()
MyWindow.show()
app.exec_()
The trick is to reference the MyWindowClass, which is the constructor of your gui and hence the GUI itself, as an object within the class that controls the content of your GUI (myGui).
You call myGui on toplevel which then calls MyWindowClass as the object self.gui. From then on, whenever you want to address something in your GUI you name it self.gui. and add the QObject.
I also tried to understand what you want to do for the pushBotton. The content of your TextEdit (in PyQt they are called lineEdit btw) is stored in the variable self.editText which is initialized as None. Afterwards, the lineEdit is cleared from the user content.

Add custom attributes to a Tk widget

My main target is to add something like an hidden tag or string to a widget, to save short information on it.
I got the idea of creating a new custom Button class (in this case I need buttons), which inherits all the old options.
This is the code:
form tkinter import *
class NButton(Button):
def __init__(self, master, tag=None, *args, **kwargs):
Button.__init__(self, master, *args, **kwargs)
self.master, self.tag = master, tag
No trouble when creating a new NButton instance:
aria1 = NButton(treewindow, bd=2, relief=GROOVE, text="Trasmissione\naerea 1", bg="#99c4ff", tag="aria 1")
aria1.place(x=20, y=20)
The problems come out when I try to get the value of tag:
aria1["tag"]
it returns:
_tkinter.TclError: unknown option "-tag"
How can I solve this?
You need to access your custom options as object attributes:
print(aria1.tag)

Signaling between parent and child widgets in tkinter

I have a moderately complex GUI that I'm building for interacting with and observing some simulations. I would like to be able to continue to refactor and add features as the project progresses. For this reason, I would like as loose as possible a coupling between different widgets in the application.
My application is structured something like this:
import tkinter as tk
class Application(tk.Tk):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.instance_a = ClassA(self)
self.instance_b = ClassB(self)
# ... #
class ClassA(tk.Frame):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# ... #
class ClassB(tk.Frame):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# ... #
def main():
application = Application()
application.mainloop()
if __name__ == '__main__':
main()
I would like to be able to perform some action in one widget (such as selecting an item in a Treeview widget or clicking on part of a canvas) which changes the state of the other widget.
One way to do this is to have the following code in class A:
self.bind('<<SomeEvent>>', self.master.instance_b.callback())
With the accompanying code in class B:
def callback(self): print('The more that things change, ')
The problem that I have with this approach is that class A has to know about class B. Since the project is still a prototype, I'm changing things all the time and I want to be able to rename callback to something else, or get rid of widgets belonging to class B entirely, or make instance_a a child of some PanedWindow object (in which case master needs to be replaced by winfo_toplevel()).
Another approach is to put a method inside the application class which is called whenever some event is triggered:
class Application(tk.Tk):
# ... #
def application_callback():
self.instance_b.callback()
and modify the bound event in class A:
self.bind('<<SomeEvent>>', self.master.application_callback())
This is definitely easier to maintain, but requires more code. It also requires the application class to know about the methods implemented in class B and where instance_b is located in the hierarchy of widgets. In a perfect world, I would like to be able to do something like this:
# in class A:
self.bind('<<SomeEvent>>', lambda _: self.event_generate('<<AnotherEvent>>'))
# in class B:
self.bind('<<AnotherEvent>>', callback)
That way, if I perform an action in one widget, the second widget would automatically know to to respond in some way without either widget knowing about the implementation details of the other. After some testing and head-scratching, I came to the conclusion that this kind of behavior is impossible using tkinter's events system. So, here are my questions:
Is this desired behavior really impossible?
Is it even a good idea?
Is there a better way of achieving the degree of modularity that I want?
What modules/tools can I use in place of tkinter's built-in event system?
My code in answer avoids the issue of class A having to know about internals of class B by calling methods of a handler object. In the following code methods in class Scanner do not need to know about the internals of a ScanWindow instance. The instance of a Scanner class contains a reference to an instance of a handler class, and communicates with the instance of ScannerWindow through the methods of Handler class.
# this class could be replaced with a class inheriting
# a Tkinter widget, threading is not necessary
class Scanner(object):
def __init__(self, handler, *args, **kw):
self.thread = threading.Thread(target=self.run)
self.handler = handler
def run(self):
while True:
if self.handler.need_stop():
break
img = self.cam.read()
self.handler.send_frame(img)
class ScanWindow(tk.Toplevel):
def __init__(self, parent, *args, **kw):
tk.Toplevel.__init__(self, master=parent, *args, **kw)
# a reference to parent widget if virtual events are to be sent
self.parent = parent
self.lock = threading.Lock()
self.stop_event = threading.Event()
self.frames = []
def start(self):
class Handler(object):
# note self and self_ are different
# self refers to the instance of ScanWindow
def need_stop(self_):
return self.stop_event.is_set()
def send_frame(self_, frame):
self.lock.acquire(True)
self.frames.append(frame)
self.lock.release()
# send an event to another widget
# self.parent.event_generate('<<ScannerFrame>>', when='tail')
def send_symbol(self_, data):
self.lock.acquire(True)
self.symbols.append(data)
self.lock.release()
# send an event to another widget
# self.parent.event_generate('<<ScannerSymbol>>', when='tail')
self.stop_event.clear()
self.scanner = Scanner(Handler())

How to extend a class instance?

I have an instance..
groupCell = QtGui.QGroupBox()
print groupCell.title() #this class has a method title()
I am not able to change anything of this instance, it comes how it is...
I need to extend this instance (add some methods etc.)
class GroupBoxWithCheckbox (QtGui.QGroupBox):
def __init__(self, basegroupbox, checkbox):
#something like self = basegroupbox ?
self.checkbox = checkbox
def method(self):
pass
and finally
groupCellWithCheckBox = GroupBoxWithCheckbox(groupCell, checkbox)
print groupCellWithCheckBox.title()
I have to get the same title as with groupCell.
You can define a new class extending QtGui.QGroupBox that looks like this:
class GroupBoxWithCheckbox(QtGui.QGroupBox):
def __init__(self, checkbox):
super(GroupBoxWithCheckbox, self).__init__()
self.checkbox = checkbox
def method(self):
pass
Then you can simply make groupCell an instance of this class, and pass in a checkbox when you initialise it:
groupCell = GroupBoxWithCheckbox(checkbox)
That will have the same effect as what you are trying to do here.
Edit, since new information has been provided:
Since we're talking Python here, you can dynamically add things to any instance you want. It's totally possible to do this:
groupCell.checkbox = checkbox
Even if the groupCell doesn't have a checkbox property. The property will be added when you set it, as in my snippet above. You could use that to do what you want. It's kind of a weird thing to do, and I don't recommend it, but it would work. The alternative is to make a wrapper class of some sort:
class GroupBoxWithCheckbox(object):
def __init__(self, groupbox, checkbox):
self.groupbox = groupbox
self.checkbox = checkbox
groupCell = GroupBoxWithCheckbox(groupCell, checkbox)
And then any time you want to access a method of the original GroupBox, you can do something like
groupCell.groupbox.title()
groupCell.groupbox will contain all of the methods that the original GroupBox did, but you'll also have access to groupCell.checkbox.
The latter solution is what I would implement if I were coding this.
Call base class constructor using super:
class GroupBoxWithCheckbox(QtGui.QGroupBox):
def __init__(self, basegroupbox, checkbox):
super(GroupBoxWithCheckbox, self).__init__()
self.checkbox = checkbox
self.basegroupbox = basegroupbox
def title(self):
return self.basegroupbox.title()

Categories

Resources