How would you design a very "Pythonic" UI framework? - python

I have been playing with the Ruby library "shoes". Basically you can write a GUI application in the following way:
Shoes.app do
t = para "Not clicked!"
button "The Label" do
alert "You clicked the button!" # when clicked, make an alert
t.replace "Clicked!" # ..and replace the label's text
end
end
This made me think - how would I design a similarly nice-to-use GUI framework in Python? One that doesn't have the usual tyings of basically being wrappers to a C* library (In the case of GTK, Tk, wx, QT etc etc)
Shoes takes things from web devlopment (like #f0c2f0 style colour notation, CSS layout techniques, like :margin => 10), and from ruby (extensively using blocks in sensible ways)
Python's lack of "rubyish blocks" makes a (metaphorically)-direct port impossible:
def Shoeless(Shoes.app):
self.t = para("Not clicked!")
def on_click_func(self):
alert("You clicked the button!")
self.t.replace("clicked!")
b = button("The label", click=self.on_click_func)
No where near as clean, and wouldn't be nearly as flexible, and I'm not even sure if it would be implementable.
Using decorators seems like an interesting way to map blocks of code to a specific action:
class BaseControl:
def __init__(self):
self.func = None
def clicked(self, func):
self.func = func
def __call__(self):
if self.func is not None:
self.func()
class Button(BaseControl):
pass
class Label(BaseControl):
pass
# The actual applications code (that the end-user would write)
class MyApp:
ok = Button()
la = Label()
#ok.clicked
def clickeryHappened():
print "OK Clicked!"
if __name__ == '__main__':
a = MyApp()
a.ok() # trigger the clicked action
Basically the decorator function stores the function, then when the action occurred (say, a click) the appropriate function would be executed.
The scope of various stuff (say, the la label in the above example) could be rather complicated, but it seems doable in a fairly neat manner..

You could actually pull this off, but it would require using metaclasses, which are deep magic (there be dragons). If you want an intro to metaclasses, there's a series of articles from IBM which manage to introduce the ideas without melting your brain.
The source code from an ORM like SQLObject might help, too, since it uses this same kind of declarative syntax.

I was never satisfied with David Mertz's articles at IBM on metaclsses so I recently wrote my own metaclass article. Enjoy.

This is extremely contrived and not pythonic at all, but here's my attempt at a semi-literal translation using the new "with" statement.
with Shoes():
t = Para("Not clicked!")
with Button("The Label"):
Alert("You clicked the button!")
t.replace("Clicked!")
The hardest part is dealing with the fact that python will not give us anonymous functions with more than one statement in them. To get around that, we could create a list of commands and run through those...
Anyway, here's the backend code I ran this with:
context = None
class Nestable(object):
def __init__(self,caption=None):
self.caption = caption
self.things = []
global context
if context:
context.add(self)
def __enter__(self):
global context
self.parent = context
context = self
def __exit__(self, type, value, traceback):
global context
context = self.parent
def add(self,thing):
self.things.append(thing)
print "Adding a %s to %s" % (thing,self)
def __str__(self):
return "%s(%s)" % (self.__class__.__name__, self.caption)
class Shoes(Nestable):
pass
class Button(Nestable):
pass
class Alert(Nestable):
pass
class Para(Nestable):
def replace(self,caption):
Command(self,"replace",caption)
class Command(Nestable):
def __init__(self, target, command, caption):
self.command = command
self.target = target
Nestable.__init__(self,caption)
def __str__(self):
return "Command(%s text of %s with \"%s\")" % (self.command, self.target, self.caption)
def execute(self):
self.target.caption = self.caption

## All you need is this class:
class MainWindow(Window):
my_button = Button('Click Me')
my_paragraph = Text('This is the text you wish to place')
my_alert = AlertBox('What what what!!!')
#my_button.clicked
def my_button_clicked(self, button, event):
self.my_paragraph.text.append('And now you clicked on it, the button that is.')
#my_paragraph.text.changed
def my_paragraph_text_changed(self, text, event):
self.button.text = 'No more clicks!'
#my_button.text.changed
def my_button_text_changed(self, text, event):
self.my_alert.show()
## The Style class is automatically gnerated by the framework
## but you can override it by defining it in the class:
##
## class MainWindow(Window):
## class Style:
## my_blah = {'style-info': 'value'}
##
## or like you see below:
class Style:
my_button = {
'background-color': '#ccc',
'font-size': '14px'}
my_paragraph = {
'background-color': '#fff',
'color': '#000',
'font-size': '14px',
'border': '1px solid black',
'border-radius': '3px'}
MainWindow.Style = Style
## The layout class is automatically generated
## by the framework but you can override it by defining it
## in the class, same as the Style class above, or by
## defining it like this:
class MainLayout(Layout):
def __init__(self, style):
# It takes the custom or automatically generated style class upon instantiation
style.window.pack(HBox().pack(style.my_paragraph, style.my_button))
MainWindow.Layout = MainLayout
if __name__ == '__main__':
run(App(main=MainWindow))
It would be relatively easy to do in python with a bit of that metaclass python magic know how. Which I have. And a knowledge of PyGTK. Which I also have. Gets ideas?

With some Metaclass magic to keep the ordering I have the following working. I'm not sure how pythonic it is but it is good fun for creating simple things.
class w(Wndw):
title='Hello World'
class txt(Txt): # either a new class
text='Insert name here'
lbl=Lbl(text='Hello') # or an instance
class greet(Bbt):
text='Greet'
def click(self): #on_click method
self.frame.lbl.text='Hello %s.'%self.frame.txt.text
app=w()

The only attempt to do this that I know of is Hans Nowak's Wax (which is unfortunately dead).

The closest you can get to rubyish blocks is the with statement from pep343:
http://www.python.org/dev/peps/pep-0343/

If you use PyGTK with glade and this glade wrapper, then PyGTK actually becomes somewhat pythonic. A little at least.
Basically, you create the GUI layout in Glade. You also specify event callbacks in glade. Then you write a class for your window like this:
class MyWindow(GladeWrapper):
GladeWrapper.__init__(self, "my_glade_file.xml", "mainWindow")
self.GtkWindow.show()
def button_click_event (self, *args):
self.button1.set_label("CLICKED")
Here, I'm assuming that I have a GTK Button somewhere called button1 and that I specified button_click_event as the clicked callback. The glade wrapper takes a lot of effort out of event mapping.
If I were to design a Pythonic GUI library, I would support something similar, to aid rapid development. The only difference is that I would ensure that the widgets have a more pythonic interface too. The current PyGTK classes seem very C to me, except that I use foo.bar(...) instead of bar(foo, ...) though I'm not sure exactly what I'd do differently. Probably allow for a Django models style declarative means of specifying widgets and events in code and allowing you to access data though iterators (where it makes sense, eg widget lists perhaps), though I haven't really thought about it.

Maybe not as slick as the Ruby version, but how about something like this:
from Boots import App, Para, Button, alert
def Shoeless(App):
t = Para(text = 'Not Clicked')
b = Button(label = 'The label')
def on_b_clicked(self):
alert('You clicked the button!')
self.t.text = 'Clicked!'
Like Justin said, to implement this you would need to use a custom metaclass on class App, and a bunch of properties on Para and Button. This actually wouldn't be too hard.
The problem you run into next is: how do you keep track of the order that things appear in the class definition? In Python 2.x, there is no way to know if t should be above b or the other way around, since you receive the contents of the class definition as a python dict.
However, in Python 3.0 metaclasses are being changed in a couple of (minor) ways. One of them is the __prepare__ method, which allows you to supply your own custom dictionary-like object to be used instead -- this means you'll be able to track the order in which items are defined, and position them accordingly in the window.

This could be an oversimplification, i don't think it would be a good idea to try to make a general purpose ui library this way. On the other hand you could use this approach (metaclasses and friends) to simplify the definition of certain classes of user interfaces for an existing ui library and depending of the application that could actually save you a significant amount of time and code lines.

I have this same problem. I wan to to create a wrapper around any GUI toolkit for Python that is easy to use, and inspired by Shoes, but needs to be a OOP approach (against ruby blocks).
More information in: http://wiki.alcidesfonseca.com/blog/python-universal-gui-revisited
Anyone's welcome to join the project.

If you really want to code UI, you could try to get something similar to django's ORM; sth like this to get a simple help browser:
class MyWindow(Window):
class VBox:
entry = Entry()
bigtext = TextView()
def on_entry_accepted(text):
bigtext.value = eval(text).__doc__
The idea would be to interpret some containers (like windows) as simple classes, some containers (like tables, v/hboxes) recognized by object names, and simple widgets as objects.
I dont think one would have to name all containers inside a window, so some shortcuts (like old-style classes being recognized as widgets by names) would be desirable.
About the order of elements: in MyWindow above you don't have to track this (window is conceptually a one-slot container). In other containers you can try to keep track of the order assuming that each widget constructor have access to some global widget list. This is how it is done in django (AFAIK).
Few hacks here, few tweaks there... There are still few things to think of, but I believe it is possible... and usable, as long as you don't build complicated UIs.
However I am pretty happy with PyGTK+Glade. UI is just kind of data for me and it should be treated as data. There's just too much parameters to tweak (like spacing in different places) and it is better to manage that using a GUI tool. Therefore I build my UI in glade, save as xml and parse using gtk.glade.XML().

Personally, I would try to implement JQuery like API in a GUI framework.
class MyWindow(Window):
contents = (
para('Hello World!'),
button('Click Me', id='ok'),
para('Epilog'),
)
def __init__(self):
self['#ok'].click(self.message)
self['para'].hover(self.blend_in, self.blend_out)
def message(self):
print 'You clicked!'
def blend_in(self, object):
object.background = '#333333'
def blend_out(self, object):
object.background = 'WindowBackground'

Here's an approach that goes about GUI definitions a bit differently using class-based meta-programming rather than inheritance.
This is largley Django/SQLAlchemy inspired in that it is heavily based on meta-programming and separates your GUI code from your "code code". I also think it should make heavy use of layout managers like Java does because when you're dropping code, no one wants to constantly tweak pixel alignment. I also think it would be cool if we could have CSS-like properties.
Here is a rough brainstormed example that will show a column with a label on top, then a text box, then a button to click on the bottom which shows a message.
from happygui.controls import *
MAIN_WINDOW = Window(width="500px", height="350px",
my_layout=ColumnLayout(padding="10px",
my_label=Label(text="What's your name kiddo?", bold=True, align="center"),
my_edit=EditBox(placeholder=""),
my_btn=Button(text="CLICK ME!", on_click=Handler('module.file.btn_clicked')),
),
)
MAIN_WINDOW.show()
def btn_clicked(sender): # could easily be in a handlers.py file
name = MAIN_WINDOW.my_layout.my_edit.text
# same thing: name = sender.parent.my_edit.text
# best practice, immune to structure change: MAIN_WINDOW.find('my_edit').text
MessageBox("Your name is '%s'" % ()).show(modal=True)
One cool thing to notice is the way you can reference the input of my_edit by saying MAIN_WINDOW.my_layout.my_edit.text. In the declaration for the window, I think it's important to be able to arbitrarily name controls in the function kwargs.
Here is the same app only using absolute positioning (the controls will appear in different places because we're not using a fancy layout manager):
from happygui.controls import *
MAIN_WINDOW = Window(width="500px", height="350px",
my_label=Label(text="What's your name kiddo?", bold=True, align="center", x="10px", y="10px", width="300px", height="100px"),
my_edit=EditBox(placeholder="", x="10px", y="110px", width="300px", height="100px"),
my_btn=Button(text="CLICK ME!", on_click=Handler('module.file.btn_clicked'), x="10px", y="210px", width="300px", height="100px"),
)
MAIN_WINDOW.show()
def btn_clicked(sender): # could easily be in a handlers.py file
name = MAIN_WINDOW.my_edit.text
# same thing: name = sender.parent.my_edit.text
# best practice, immune to structure change: MAIN_WINDOW.find('my_edit').text
MessageBox("Your name is '%s'" % ()).show(modal=True)
I'm not entirely sure yet if this is a super great approach, but I definitely think it's on the right path. I don't have time to explore this idea more, but if someone took this up as a project, I would love them.

Declarative is not necessarily more (or less) pythonic than functional IMHO. I think a layered approach would be the best (from buttom up):
A native layer that accepts and returns python data types.
A functional dynamic layer.
One or more declarative/object-oriented layers.
Similar to Elixir + SQLAlchemy.

Related

Python classes keep calling eachother

I have been trying to use classes for both of my files. I made a gui.py with:
class GuiStart:
def __init__(self, master):
self.master = master
self.master.title("DECTools 1.3")
I have another file with methods I want to execute. This file is called foo.py
class DecToolsClass:
def __init__(self):
self.gui = gui.GuiStart()
I get an error, because I don't give the it the master parameter. I can't set it to None because it doesn't have the .title method.
I execute the gui file with:
if __name__ == "gui":
root = tkinter.Tk()
my_gui = GuiStart(root)
root.mainloop()
The problem is that I need to execute a method from foo.py with my gui.py file and I need to access attributes from my gui.py file with my foo.py file. I have been trying to accomplish this and I know I can't use multiple constructors like in Java.
Is it possible what I want or do I have to rewrite my code?
Thanks in advance!
The GuiStart class starts the tkinter gui. The window with buttons and entries is created with that class. From the GuiStart class I call methods that do things like copy files to a certain location
Alright, so to sum it up, you have a class that handles user interaction, and a set of generic methods doing no user interaction, that GuiStart provides a Gui for. If I understand wrong, this answer will be much less useful.
It is indeed a good idea to split those, but for this split to be effective, you must not have direct references from one another. This means this is a definitive DON'T:
class DecToolsClass:
def __init__(self):
self.gui = gui.GuiStart()
If you actually needed the tools to access the gui, you'd inject it. But normally you would want it the other way around: Tools should be generic and not know about Gui at all. Onn the other hand, Gui knows about them. Assuming the rest of the code is correct (I don't know tkinter):
def main():
tools = DecToolsClass() # not shown, but it no longer has self.gui
root = tkinter.Tk()
my_gui = gui.GuiStart(root, tools)
root.mainloop()
if __name__ == '__main__':
main()
Which means of course GuiStart must take the toolset it will use as an argument:
class GuiStart:
def __init__(self, master, tools):
self.master = master
self.master.title("DECTools 1.3")
self.tools = tools
Now, everywhere in GuiStart, any use of tools must go through self.tools. As an added bonus, in your unittests you can pass a dummy tools object that just checks how it is called, that makes testing very easy.

PyQt obtaining collection of all registered fields in QWizard

I am working on a simple QWizard that displays some radio buttons on its pages. The buttons on a given page are all part of the same QButtonGroup. The page is registered as a custom field in itself, based on the selection in the button group:
class Page1(QWizardPage):
selectionChanged = pyqtSignal('QString')
def __init__(self, name):
self.group = QButtonGroup()
self.group.addButton(QRadioButton("a"))
self.group.addButton(QRadioButton("b"))
self.group.addButton(QRadioButton("c"))
self.registerField(name, self, 'selection', self.selectionChanged)
#pyqtProperty('QString')
def selection(self):
checkedButton = self.group.checkedButton()
return checkedButton.text() if checkedButton else None
def nextId(self): return -1
I end up registering self as the widget containing the field property simply because QButtonGroup is not a QWidget. All of the other pages look pretty much exactly like this (I am actually using base class to do all the common work, and this is just a minimal example).
I would like to be able to get a list of all the registered fields in the QWizard. I have not found any methods provided by Qt to allow me to do this so I made a workaround by overriding the behavior of each page's registerField method as well as the wizard's addPage:
def registerField(self, name, *args, **kwargs):
self.field_names.add(name)
if self.wizard() is not None:
self.wizard().field_names.add(name)
super().registerField(name, *args, **kwargs)
def addPage(self, page, *args, **kwargs):
self.field_names.union(page.field_names)
return super().addPage(page, *args, **kwargs)
I can then use the field_set attribute of the parent QWizard combined with QWizard.field to access all the values. This seems a bit redundant and therefore unnecessary. Is there a method in Qt to access the complete collection of fields? The relevant section in the documentation does not mention anything, but there are a lot of other details it omits, so that's not very telling.
My assumption is that the functionality, if it exists, would be the same for PyQt4 as for PyQt5. If it is not, I would prefer an answer for PyQt5 since that is what I am using at the moment.
You said that if the answer is negative it would have to be "pretty convincing." You admit that the documentation contains no mention of the function you want, and I will point out that no such function appears in the list of public functions for QWizard. Therefore the desired function, if it exists at all, is undocumented. To me, that consideration alone would be a "pretty convincing" reason not to use it. The next release of Qt might not have that function, or it might not work the same way.
Meanwhile you have an acceptable solution with eight lines of straightforward python code. Given the choice between that and calling an undocumented function (if you can find it), the python solution is vastly superior in all practical respects.
There is a potential problem with your Python code, however. You override the function QWizard.addPage, but there is another function QWizard.removePage that should probably be overridden as well. An alternative approach, which I would prefer, is not to store the field_names in QWizard at all but only in the individual pages. Add a method to QWizard to dynamically build a set of all the current field_names:
def all_field_names(self):
return {s for page_id in self.pageIds() for s in self.page(page_id).field_names}
[I didn't have a good way of testing this function, but I think you get the idea.] Now you remove the overridden method QWizard.addPage, remove the variable field_names from QWizard, and remove the middle two lines of register_field. Now you have only five lines of Python code, which will work regardless of how pages are added or removed. And you no longer store the field names in two places.
For what it's worth, whenever I'm confronted with a choice between using Qt's functionality or basic Python functionality, I always lean toward Python. I use threads instead of QThreads, threading locks and timers instead of Qt equivalents, Python method objects and callbacks instead of custom Slots and Signals. Qt was written for C++ programmers and that often means that it's not as "pythonic" as I would like.

Single Responsibility Principle for CRUD operations against a collection

I'm trying to understand how to logically separate CRUD responsibilities so to adhere to the Single Responsibility Principle (SRP).
As I understand the definition of SRP, a single responsibility may not necessarily be a single behavior, but instead be a collection of behaviors with a well-defined, logical boundary from others.
In my example, RestaurantMenu is nothing more than a collection. I understand that there are more efficient ways to represent this, such as with a dictionary, but that is beyond the intent of this example. My RestaurantMenu has no behavior assigned to it because it remains unclear to me as to whether defining any further behavior by it would breach the SRP. It feels rather uncomfortable instantiating and calling separate CRUD objects through a Manager object rather than through methods in RestaurantMenu, so that is why I've decided to ask the audience here for some guidance.
Does the following example pass the SRP litmus test?
class RestaurantMenu(object):
def __init__(self, title, creator, catalog_type, restaurant):
self._title = title
self._creator = creator
self._catalog_type = catalog_type
self._restaurant = restaurant
self._menuitems = dict()
class MenuManager(object):
"""Responsibility
--------------
Coordinates CRUD related activities with a menu
"""
def __init__(self, menu):
self._menu = menu
def add_menu_item(self, item, value):
menu_item_adder = AddMenuItem(self._menu)
menu_item_adder(item, value)
def del_menu_item(self, item):
menu_item_deleter = DelMenuItem(self._menu)
menu_item_deleter(item)
def update_menu_item(self, existing_item, new_info):
menu_item_updater = UpdateMenuItem(self._menu)
menu_item_updater(existing_item, new_info)
def get_menu_items(self):
menu_item_getter = GetMenuItems(self._menu)
menu_item_getter()
class GetMenuItems(object):
def __init__(self, menu):
self._menu = menu
def __call__(self):
print(self._menu._title)
print('='*len(self._menu._title))
for key, value in self._menu._menuitems.items():
print(key, value)
class AddMenuItem(object):
def __init__(self, menu):
self._menu = menu
def __call__(self, item, value):
if item not in self._menu._menuitems:
self._menu._menuitems[item] = value
print('Item added:', item)
else:
print('Item already exists. Please update instead.')
class DelMenuItem(object):
def __init__(self, menu):
self._menu = menu
def __call__(self, item):
popped = self._menu._menuitems.pop(item)
print('Item removed:', popped)
class UpdateMenuItem(object):
def __init__(self, menu):
self._menu = menu
def __call__(self, existing_item, new_info):
self._menu._menuitems.update(existing_item=new_info)
print('Item updated:', existing_item, ' with', new_info)
def main():
mymenu = RestaurantMenu("Joe's Crab Shack 2014 Menu",
"Joe Schmoe",
"Restaurant",
"Joe's Crab Shack")
menumanager = MenuManager(mymenu)
menumanager.add_menu_item('longneck_clams', 7.00)
menumanager.add_menu_item('1 pound lobster', 15.00)
menumanager.add_menu_item('lobster chowder', 9.00)
print('-'*50)
menumanager.get_menu_items()
if __name__ == "__main__":
main()
One possible definition of SRP compliance is that there should only be one reason for a class to change.
This makes it very hard to call SRP or not on a piece of code in the abstract -- it basically depends on what will happen to evolve together and separately over time in your application.
Generally speaking though, the UI is one of the primary things that might evolve independently from other parts of a program. Users will keep wanting to make little display adjustments over the course of a project, and it's a nice thing to be able to modify the presentation logic without fearing to break the rest of the system. Persistence is another thing you might want to change, either as a result of new architectural decisions or temporarily, depending on the context (swapping in dummy persistence objects in tests for instance).
This is why in most real-world applications, I would tend to split up classes by technical responsibility rather than business operations on a same entity like C/R/U/D.
If you look closely at your current implementation, you'll notice patterns in your classes. They all fiddle with a MenuManager and the MenuItems stored in it. They all print things to the screen.
If you want to change something in the way data is displayed or stored, you'll basically have to touch all these classes. I'm not saying it's a serious flaw in the case of a small simple system like this, but in a larger application it might well be a problem.
Put another way, your example makes it easy to have menu updates done through a graphical interface into a SQL database, menu inserts done via a command shell into flat files, and menu reads spitting out an XML file with data gathered from a web service. This might be what you want to do in very particular circumstances, but not most of the time...
I just want to complement #guillaume31 answer, but I don't think it will fit in a comment.
As I understand the definition of SRP, a single responsibility may not necessarily be a single behavior, but instead be a collection of behaviors with a well-defined, logical boundary from others.
However you say you understand this, your code shows the opposite. You've spread a high cohesive group of tasks through several classes. Why this is bad?
How many times do you have the following code?
def __init__(self, menu):
self._menu = menu
I'm to lazy to count it, but you'll notice that this is an unecessary code duplication.
In this particular simple case, there is no problem, in deed, but if you application grow, you'll have a huge headache.
In some countries, it's valentine's day tomorrow, so you should remember how to KISS.

Splitting PyQt Code - Passing Main App By Reference Or Import

Am having much trouble splitting PyQt code:
main.py
(PyQt modules)
from titles import *
appl = QApplication(sys.argv)
from main import Ui_MainWindow
class Main(QMainWindow):
def __init__(self, parent=None):
super(Main, self).__init__(parent)
QMainWindow.__init__(self)
self.u = Ui_MainWindow()
self.u.setupUi(self)
Titles(self)
titles.py
import sys
(PyQt modules)
(dbconnections)
class Titles():
def __init__(self, a): #<-- APP IS PASSED AS ARGUMENT AND NOW CALLED 'A'
a.u.table.setModel(titles)
a.u.lineEdit.setText("Titles Init")
a.u.add.clicked.connect(titles.insertRow)
class TitlesTableModel(QSqlTableModel):
def __init__(self):
QSqlTableModel.__init__(self)
self.setTable("titles")
self.setEditStrategy(self.OnFieldChange)
self.select()
def insertRow(self):
return self.insertRecord(-1, self.record())
a.u.lineEdit.setText("Insert Title")
titles = Titles()
Running main.py loads all data. QPushButton inserts a row, but doesn't set lineEdit to "Insert Title", because "a" isn't defined globally. Mostly tried creating a function in titles.py, triggered when main.py loads, looking like:
a = 0 #<-- THIS WAS A LAST STRAW AS WARNED BY RESEARCHING OTHERS, BUT AM LOST
def start(app):
global a
a = app
Titles(a); TitlesTableModel(a) #<-- EVEN THOUGH TITLES.PY IS IMPORTED, IT DIDN'T INCLUDE THE APP REFERENCE, SO AM TRYING TO 'REFRESH' THE TITLESTABLEMODEL
...with Titles & TitlesTableModel requiring an extra argument (self, a)
This loads data & functions, but again, insertRow doesn't update lineEdit.
Other attempt
change Songs class to
class Songs():
def __init__(self, a):
titles = Titles(a)
...(rest the same)
...and removing titles=Titles() from below the model definition. This again, shows data, but doesn't update lineEdit when pressing 'Add'.
Ultimately, it feels titles.py needs to have 'from main import *', but the main applications instance is defined after titles.py is called, and importing main.Main creates a recursion. Have tried inheriting multiple times via 'from main import Main', & writing 'class Songs(Main)' (so Songs can use the UI without passing a reference), but again, recursion occurs. Nine hours today plus three weeks prior looking at others, so am really stumped. Others somewhat recommended using a config file of even 'builtin', but that looks very bad.
Regards
In PyQt, classes generally use Signals to communicate between one another, especially when one class inherits from QWidget and the other does not inherit from that, as you've demonstrated by connecting signals (albeit wrongly, or at least you're missing bits and pieces of your code here on SO).
However, your insertRow() -> lineEdit method as it stands will never be called because it follows a return statement, meaning that the lineEdit part will never be hit. But I would be surprised if this fixed the problem.
Also, I would consider redesigning (refactoring) your code from the grounds up. Is there really a reason you have a different Titles() class?
While this is shameless self-promotion, I think you might benefit from my course on YouTube that deals with building Python applications using PySide (which is nearly identical to PyQt) - I discuss cross-thread (cross-class) communication a fair bit - link is http://youtube.com/Deusdies2
Your code has several issues, but the main problem is the snippet:
def insertRow(self):
return self.insertRecord(-1, self.record())
a.u.lineEdit.setText("Insert Title")
as you can see you're returning from the function before the line a.u.lineEdit.setText("Insert Title") get excecuted. Hence, this function willl never change the text of your QLineEdit.
Change your code b
def insertRow(self):
a.u.lineEdit.setText("Insert Title") # First change text.
return self.insertRecord(-1, self.record()) # Then insert record and return.
On the other hand: If you are working with global variables (a bad practice, I have to say) why are you passing it as arguments? Try to not use global variables at least is absolutly necesary.

wxpython passing information, pointers?

I'm trying to code up an application to help me keep track of my students. Basically a customized notebook/gradebook. I hacked something together last summer that worked for this past year, but I need something better.
I'm going to pull each students record from a database, display it on my main page and have elements clickable to open a frame so that I can edit it. I need to pass information between these two frames and I'm an idiot because I can't seem to figure out how to alter the examples I've come across showing lambdas and same-class information passing.
On my main window I have a StaticText that looks like this
self.q1a_lbl = wx.StaticText(id=wxID_MAINWINDOWQ1A_LBL, label=u'87%',
name=u'q1a_lbl', parent=self.alg_panel, pos=wx.Point(115, 48),
size=wx.Size(23, 17), style=0)
self.q1a_lbl.SetToolTipString(u'Date \n\nNotes')
self.q1a_lbl.Bind(wx.EVT_LEFT_UP, self.OnQ1a_lblLeftUp)
Then I have the function:
def OnQ1a_lblLeftUp(self, event):
import quiz_notes
quiz_notes.create(self).Show(True)
Which works graphically, but I'm not really doing anything other than opening a window when the text is clicked on. Then I have another Frame with
import wx
def create(parent):
return quiz_notes(parent)
[wxID_QUIZ_NOTES, wxID_QUIZ_NOTESCANCEL_BTN, wxID_QUIZ_NOTESDATEPICKERCTRL1,
wxID_QUIZ_NOTESENTER_BTN, wxID_QUIZ_NOTESPANEL1, wxID_QUIZ_NOTESTEXTCTRL1,
] = [wx.NewId() for _init_ctrls in range(6)]
class quiz_notes(wx.Frame):
def _init_ctrls(self, prnt):
...and so on
I would like to pass at least a couple of variables. Eventually, when I start integrating the database into it, I would just pass a tuple. Or a reference to it. In C I'd just use a pointer. Anyway, make changes and then go back to my main window. In short, whats the best way to work with data between these two classes?
There are not pointers in Python, but there are mutable structures. You can share state between objects by handing the same state-object to multiple instances.
What that state-object should be depends entirely on what you're trying to do (I still have no idea). It could be anything mutable, a module, class, instance, dict or list.
In this example the shared state is a list in a global variable:
# a list is mutable
state = 'Hello World'.split()
class Class1:
def hi(self):
print ' '.join(state)
# do something to the shared state
state[0] = 'Bye'
class Class2:
def hi(self):
print ' '.join(state)
x = Class1()
y = Class2()
x.hi()
y.hi()
Check out Mike Driscoll's blog post on using PubSub in wxPython.
It's using the included PubSub in wxPython - just be aware that it is a stand-alone library, and the latest version's API is different to the one included in wx (a better API, if I may say so)

Categories

Resources