#!/usr/bin/python
# -*- coding: ISO-8859-1 -*-
from gi.repository import GLib, Gtk, Gio
import sys
from gi.repository import Gdk
from gi.repository.GdkPixbuf import Pixbuf, InterpType
class MyAbout(Gtk.AboutDialog):
__gtype_name__ = 'MyAbout' # nom pour css
def __init__(self,title='',version="1.0",\
authors=["Francis"],\
name="PyGObject Tutorial",\
comment="New tutorial on using Python with GTK+ 3",\
website="http://www.learngtk.org/",\
label="LearnGTK Website",\
filename=None,\
size_x=100, size_y=100):
Gtk.AboutDialog.__init__(self)
self.set_title(title)
self.set_version(version)
self.set_authors(authors)
if filename is not None:
file = filename
else:
file = "/home/francis/Documents/Python-linux/demo_gtk2/battery.png"
pixbuf = Pixbuf.new_from_file_at_size(file,size_x, size_y)
self.set_logo(pixbuf)
self.set_name(name)
self.set_comments(comment)
self.set_website(website)
self.set_website_label(label)
__version__ = "V1_30"
class MyApp_root(object):
""" just a little app with few menu """
def __init__(self):
GLib.set_application_name('My App')
self.app = Gtk.Application.new('org.example.test', 0)
self.app.connect('startup', self.on_app_startup)
self.app.connect('activate', self.on_app_activate)
self.app.connect('shutdown', self.on_app_shutdown)
def add_sub_menu(self,texte, menu):
""" just add submenu to menu return need reference to sub_menu"""
submenu = Gio.Menu()
menu.append_submenu(texte, submenu)
return submenu
def add_menu_bar(self,app):
""" just add function menubar app need refernce to app_menu"""
menu_bar = Gio.Menu()
app.set_menubar(menu_bar)
return menu_bar
def add_section(self,app):
""" just add a section
note between 2 sections there is a separator"""
section = Gio.Menu()
app.append_section(None, section)
return section
def add_simple_action(self, app, name, callback):
""" in order to create callback fonction linked menu"""
action = Gio.SimpleAction.new(name, None)
action.connect('activate', callback)
app.add_action(action)
def add_menuitem(self,section,text,link,attribut_type=None, attribut_value=None):
""" just add a item with parameter """
item = Gio.MenuItem.new(text,link)
if attribut_type is not None:
# example item.set_attribute_value("accel", GLib.Variant("s", "<Control>Q"))
item.set_attribute_value(attribut_type, attribut_value)
section.append_item(item)
def run(self, argv):
""" in order to run class """
self.app.run(argv)
def on_app_startup(self, app):
""" auto start app in window, set menu and call back
standard design in python callback action is action_cb"""
self.window = Gtk.ApplicationWindow.new(app)
self.window.set_default_size(640, 480)
self.window.set_title('AppMenu Demo')
app.add_window(self.window)
# # add Appmenu to app
self.app_menu = Gio.Menu()
section = self.add_section(self.app_menu)
self.add_menuitem(section,'Quit', 'app.quit',"accel", GLib.Variant("s", "<Control>Q"))
# it's necessary to link app-menu to app after section definition if not accelerator don't operate
app.set_app_menu(self.app_menu)
self.add_simple_action(app,'quit',self.quit_cb)
self.add_simple_action(app,'histo',self.histo_cb)
self.add_simple_action(app,'about',self.about_cb)
self.add_simple_action(app,'help',self.help_cb)
# # Menu bar attached app
self.menu_bar = self.add_menu_bar(app)
#---création submenu1
self.submenu1 = self.add_sub_menu('Miscellaneous',self.menu_bar)
#---création de section 3
section3 = self.add_section(self.submenu1)
#---gestion des item
self.add_menuitem(section3,'Help', 'app.help',"accel", GLib.Variant("s", "<Control>H"))
self.add_menuitem(section3,'About', 'app.about')
self.add_menuitem(section3,'Historic version', 'app.histo')
#code writed here in order to debug
submenu1 = self.add_sub_menu('Miscellaneous 1',self.menu_bar)
# # add section to submenu
section1 = self.add_section(submenu1)
# add item to section
self.add_simple_action(app,'pref',self.pref_cb)
self.add_menuitem(section1,'Preference', 'app.pref',"accel", GLib.Variant("s", "<Control>P"))
def on_app_activate(self, app):
self.window.show_all()
def on_app_shutdown(self, app):
pass
#here only in order to debug corresponding part and deleted after
def pref_cb(self, action, data=None):
print 'action preference not dev !!!!!!!!'
# end block to be deleted
def histo_cb(self, action, data=None):
print 'historique des versions'
print 'Version 1.30 add root class with basic menu '
print '#Version 1.31 > a class inherit MyApp_root and try to add something'
def about_cb(self, action, data=None):
about = MyAbout(version=__version__)
about.run()
def help_cb(self, action, data=None):
print "aide non developpe"
def quit_cb(self, action, data=None):
self.app.quit()
class MyAppNew(MyApp_root):
""" inherit class MyApp_root """
def __init__(self):
MyApp_root.__init__(self);
# # add submenu attached menu_bar
submenu = self.add_sub_menu('Miscellaneous next',self.menubar) #error here AttributeError: 'MyAppNew' object has no attribute 'menubar'
section1 = self.add_section(submenu)
# add item to section
self.add_menuitem(section1,'work hard', 'app.work')
self.add_simple_action(app,'work',self.work_cb)
def run(self, argv):
""" in order to run class """
pass # ??????
# here start to transfer all call back not necessary in root class
def work_cb(self, action, data=None):
print " It's very hard for me to make a class inherit class MyApp_root"
# to adapt a new help
def help_cb(self, action, data=None):
print "How to implement polymorhisme in order to change action in th child class here ??"
if __name__ == '__main__':
new_test = True
if new_test:
app = MyAppNew()
else:
application = MyApp_root()
application.run(sys.argv)
Hello everybody,
I know why error occur , self.menubar is not created in the init of root MyApp_root. But its created with self.on_app_startup when event 'startup' occur.
during start running class. Ok it's said
but now who could help me and say me how I must operate to add some new submenu in MyAppNew. Thank a lot by advance
In this case assuming you really want to work like this the solution is to make sure that you add the new submenu after self.menu_bar is created.
In your case the easiest way to do this is adding a function like self.insert_custom_menu (or something like that) in MyApp_root which you will overwrite in MyAppNew. If you then have a function call to this function in on_app_startup it will be easy to add the new menu options
So for example in MyApp_root the function will be like this:
def insert_custom_menu(self):
pass
While in MyAppNew the function will be like this:
def insert_custom_menu(self):
submenu = self.add_sub_menu('Miscellaneous next',self.menubar)
section1 = self.add_section(submenu)
self.add_menuitem(section1,'work hard', 'app.work')
The reason why this will work is that MyAppNew does not try to add something to a menu during init while the menu is only create after the startup signal. With the above solution the custom part of the menu is also loaded after startup which resolves the issue at hand.
In order to help. A example of inherit class Gtk.Application. It's running on my linux except bug unity on top menu ""Unknown Application Name"" appear instead of really name it's know.
it's just a modest contribution
#!/usr/bin/python
# -*- coding: ISO-8859-1 -*-
from gi.repository import GLib, Gtk, Gio
import sys
from gi.repository import Gdk
from gi.repository.GdkPixbuf import Pixbuf, InterpType
class MyAbout(Gtk.AboutDialog):
__gtype_name__ = 'MyAbout' # nom pour css
def __init__(self,title='',version="1.0",\
authors=["Francis"],\
name="PyGObject Tutorial",\
comment="New tutorial on using Python with GTK+ 3",\
website="http://www.learngtk.org/",\
label="LearnGTK Website",\
filename=None,\
size_x=100, size_y=100):
Gtk.AboutDialog.__init__(self)
self.set_title(title)
self.set_version(version)
self.set_authors(authors)
if filename is not None:
file = filename
else:
file = "/home/francis/Documents/Python-linux/demo_gtk3/battery.png"
try:
pixbuf = Pixbuf.new_from_file_at_size(file,size_x, size_y)
self.set_logo(pixbuf)
except:
self.set_name(name)
self.set_comments(comment)
self.set_website(website)
self.set_website_label(label)
__version__ = "V1_30"
class MyApp_root(object):
""" just a little app with few menu """
def __init__(self):
GLib.set_application_name('My App')
self.app = Gtk.Application.new('org.example.test', 0)
self.app.connect('startup', self.on_app_startup)
self.app.connect('activate', self.on_app_activate)
self.app.connect('shutdown', self.on_app_shutdown)
def add_sub_menu(self,texte, menu):
""" just add submenu to menu return need reference to sub_menu"""
submenu = Gio.Menu()
menu.append_submenu(texte, submenu)
return submenu
def add_menu_bar(self,app):
""" just add function menubar app need refernce to app_menu"""
menu_bar = Gio.Menu()
app.set_menubar(menu_bar)
return menu_bar
def add_section(self,app):
""" just add a section
note between 2 sections there is a separator"""
section = Gio.Menu()
app.append_section(None, section)
return section
def add_simple_action(self, app, name, callback):
""" in order to create callback fonction linked menu"""
action = Gio.SimpleAction.new(name, None)
action.connect('activate', callback)
app.add_action(action)
def add_menuitem(self,section,text,link,attribut_type=None, attribut_value=None):
""" just add a item with parameter """
item = Gio.MenuItem.new(text,link)
if attribut_type is not None:
# example item.set_attribute_value("accel", GLib.Variant("s", "<Control>Q"))
item.set_attribute_value(attribut_type, attribut_value)
section.append_item(item)
def run(self, argv):
""" in order to run class """
self.app.run(argv)
def insert_custom_menu(self):
""" in order to add custom menu later"""
pass
def insert_custom_submenu_first(self):
""" in order to add something in the first submenu before Quit """
## current section is self.custom_section
pass
def insert_custom_submenu_last(self):
""" in order to add something in the last submenu before Quit """
## current section is self.custom_section_last
pass
def on_app_startup(self, app):
""" auto start app in window, set menu and call back
standard design in python callback action is action_cb"""
self.window = Gtk.ApplicationWindow.new(app)
self.window.set_default_size(640, 480)
self.window.set_title('AppMenu Demo')
app.add_window(self.window)
# # add Appmenu to app
self.app_menu = Gio.Menu()
# insert something in the first submenu in dedicated section
self.custom_section = self.add_section(self.app_menu)
self.insert_custom_submenu_first()
# last section to quit action
section_last = self.add_section(self.app_menu)
self.add_menuitem(section_last,'Quit', 'app.quit',"accel", GLib.Variant("s", "<Control>Q"))
# it's necessary to link app-menu to app after section definition if not, accelerator don't operate
app.set_app_menu(self.app_menu)
self.add_simple_action(app,'quit',self.quit_cb)
self.add_simple_action(app,'histo',self.histo_cb)
self.add_simple_action(app,'about',self.about_cb)
self.add_simple_action(app,'help',self.help_cb)
# # Menu bar attached app
self.menu_bar = self.add_menu_bar(app)
# planed if custum menu
self.insert_custom_menu()
#---make submenu1
self.submenu1 = self.add_sub_menu('Miscellaneous',self.menu_bar)
#---make section 3
section3 = self.add_section(self.submenu1)
#---item management
self.add_menuitem(section3,'Help', 'app.help',"accel", GLib.Variant("s", "<Control>H"))
self.add_menuitem(section3,'About', 'app.about')
self.add_menuitem(section3,'Historic version', 'app.histo')
## last section dedicated to custom add in last submenu
self.custom_section_last= self.add_section(self.submenu1)
self.insert_custom_submenu_last()
def on_app_activate(self, app):
self.window.show_all()
def on_app_shutdown(self, app):
pass
def histo_cb(self, action, data=None):
print 'historique des versions'
print 'Version 1.30 add root class with basic menu '
print '#Version 1.31 > a class inherit MyApp_root and try to add something'
def about_cb(self, action, data=None):
""" about app"""
about = MyAbout(version=__version__)
about.run()
def help_cb(self, action, data=None):
""" in order to help user """
print "aide non developpe"
def quit_cb(self, action, data=None):
self.app.quit()
class MyAppNew(MyApp_root):
""" inherit class MyApp_root """
def __init__(self):
MyApp_root.__init__(self);
def run(self, argv):
""" in order to run class """
self.app.run(argv)
def insert_custom_submenu_first(self):
""" in order to add something in the first submenu before Quit """
## current section is self.custom_section
self.add_menuitem(self.custom_section,'something 1', 'app.work1')
self.add_simple_action(self.app,'work1',self.work1_cb)
def insert_custom_menu(self):
""" custom menu in child class"""
submenu1 = self.add_sub_menu('Miscellaneous next',self.menu_bar)
# # add section to submenu
section1 = self.add_section(submenu1)
# add item to section
self.add_menuitem(section1,'work hard', 'app.work')
self.add_simple_action(self.app,'work',self.work_cb)
def insert_custom_submenu_last(self):
""" in order to add something in the last submenu before Quit """
## current section is self.custom_section_last
self.add_menuitem(self.custom_section_last,'something in the last submenu', 'app.work2')
self.add_simple_action(self.app,'work2',self.work2_cb)
def work_cb(self, action, data=None):
print " It's very hard for me to make a class inherit class MyApp_root"
def work1_cb(self, action, data=None):
print " something 1"
def work2_cb(self, action, data=None):
print " ready to do something in the last submenu"
# to adapt a new help
def help_cb(self, action, data=None):
print "How to implement overwrite method in order to change action in child class here"
if __name__ == '__main__':
app = MyAppNew()
app.run(sys.argv)
Related
I am trying to get a file upload form field working in Django and the part I am having problems with is dynamically changing the form field required attribute. I have tried using "self.fields['field_name'].required=True' in the init method of the form but that isn't working for me.
I have looked at Django dynamically changing the required property on forms but I don't want to build several custom models and a custom render function for one form as surely it must be easier than that.
The reason I am trying to do this is because when a django form validates and has errors it doesn't pass any uploaded files back to the browser form for reediting. It will pass text areas and text inputs that didn't validate back to the form for reediting but not file uploads. I thought if I made the file upload fields mandatory for the first time the record is created mandatory and for subsequent times make them optional. That is basically what I am trying to do.
So here is what I have been trying so far:
In forms.py
from django.forms import fields
from .widgets import PDFUploadWidget, PlainTextWidget
class WQPDFField(fields.Field):
widget = PDFUploadWidget
def widget_attrs(self, widget):
attrs = super().widget_attrs(widget)
attrs['label'] = self.label
return attrs
def clean(self, *args, **kwargs):
return super().clean(*args, **kwargs)
In widgets.py
from django.forms import widgets
from django.utils.safestring import mark_safe
# We subclass from HiddenInput because we want to suppress the printing
# of the label and prefer to print it ourselves.
class PDFUploadWidget(widgets.HiddenInput):
template_name = 'webquest_widgets/widgets/pdf_upload.html'
input_type = 'file'
def __init__(self, *args, **kwargs):
style = 'visibility:hidden'
attrs = kwargs.pop('attrs', None)
if attrs:
attrs['style'] = style
else:
attrs = {'style':style}
attrs['accept'] = '.pdf'
print (attrs)
super().__init__(attrs)
def get_context(self, name, value, attrs):
context = super().get_context(name, value, attrs)
return context
#property
def is_hidden(self):
return True
class Media:
css = { 'all': ( 'css/pdfupload.css', ) }
js = ('js/pdfupload.js', )
and finally in forms.py
class WorkWantedForm(forms.Form):
category = forms.ChoiceField(choices=CHOICES)
about = forms.CharField(label="About Yourself", widget=forms.Textarea())
static1 = WQStaticField(text="Enter either phone or email")
phone = forms.CharField(required=False)
email = forms.EmailField(required=False)
cv = WQPDFField(label="Upload CV")
supporting_document = WQPDFField(label="Supporting Document (optional)", required=False)
I am not sure how to pass the "required" attribute to the custom field class after the initialisation of the form but before rendering the form as HTML.
In my program i want to use key press event in list view.When i press the enter key then only my selected text will print..Can any one please tell me how to use key press event for list view.I tried with installEventFilter but this method showing non type error.
Given below is my code:
import sys
from PyQt4 import QtCore,QtGui
class List_View(QtGui.QMainWindow):
def __init__(self, parent=None):
super(List_View, self).__init__(parent)
self.listview = QtGui.QListView()
model = QtGui.QStandardItemModel(self.listview)
for i in ['linux', 'windows', 'mac os']:
model.appendRow(QtGui.QStandardItem(i))
self.listview.setModel(model)
self.listview.entered.connect(self.add_items)
widget = QtGui.QWidget()
self.setCentralWidget(widget)
vlay = QtGui.QVBoxLayout(widget)
vlay.addWidget(self.listview)
self.resize(400, 200)
def add_items(self):
pass #here i need to print particular item in list view
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
w = List_View()
w.show()
sys.exit(app.exec_())
I think you have not read the docs of the entered signal or you have not understood it, that signal only triggers when the mouse is on the item but for this you must activate the mouse tracking with self.listview.setMouseTracking(True)
A simple solution is to use a QShortcut:
import sys
from PyQt4 import QtCore,QtGui
class List_View(QtGui.QMainWindow):
def __init__(self, parent=None):
super(List_View, self).__init__(parent)
shorcut = QtGui.QShortcut(
QtGui.QKeySequence(QtCore.Qt.Key_Return),
self
)
shorcut.activated.connect(self.on_enter_pressed)
self.listview = QtGui.QListView()
model = QtGui.QStandardItemModel(self.listview)
for i in ['linux', 'windows', 'mac os']:
model.appendRow(QtGui.QStandardItem(i))
self.listview.setModel(model)
widget = QtGui.QWidget()
self.setCentralWidget(widget)
vlay = QtGui.QVBoxLayout(widget)
vlay.addWidget(self.listview)
self.resize(400, 200)
#QtCore.pyqtSlot()
def on_enter_pressed(self):
print("enter press")
ix = self.listview.selectionModel().currentIndex()
print(ix.data())
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
w = List_View()
w.show()
sys.exit(app.exec_())
The user enters values using line edits on the MyWidget screen and then presses the Enter button. This opens the MyDialog screen on which data will be plotted when the Run button is pressed. How can I make the line edit data accessible to run in MyDialog for plotting? Or, is there a better way of doing this which wouldn't require passing variables between classes? My program is based on this answer.
from PyQt4 import QtCore, QtGui, uic
# Import Qt widgets
from matplotlib.backends.backend_qt4agg \
import FigureCanvasQTAgg as FigureCanvas
from matplotlib.backends.backend_qt4agg \
import NavigationToolbar2QT as NavigationToolbar
from matplotlib.figure import Figure
GUI_FILE = "Minimal_UI.ui" # GUI with line edit and 'enter' button
form_class = uic.loadUiType(GUI_FILE)[0]
class MyWidget(QtGui.QWidget, form_class):
def __init__(self, parent=None):
super(MyWidget, self).__init__(parent)
self.setupUi(self)
self.pushButton_Enter.clicked.connect(self.on_pushButton_clicked)
self.dialogTextBrowser = MyDialog(self)
#QtCore.pyqtSlot()
def on_pushButton_clicked(self):
# I'd like to be able to pass Temp_0 to the run method
self.Temp_0 = self.lineEdit_Temp_0.text()
self.dialogTextBrowser.exec_()
class MyDialog(QtGui.QDialog):
def __init__(self, parent=None):
super(MyDialog, self).__init__(parent)
self.fig = Figure()
self.canvas = FigureCanvas(self.fig)
self.toolbar = NavigationToolbar(self.canvas, self)
self.run_button = QtGui.QPushButton('Run')
self.run_button.clicked.connect(self.run)
self.stop_button = QtGui.QPushButton('Stop')
self.stop_button.clicked.connect(self.stop)
layout = QtGui.QVBoxLayout()
# Widgets are stacked in the order they are added
layout.addWidget(self.toolbar)
layout.addWidget(self.canvas)
layout.addWidget(self.run_button)
layout.addWidget(self.stop_button)
self.setLayout(layout)
def run(self):
# Create axes
ax = self.fig.add_subplot(111)
# Discard the old graphs
ax.hold(False)
# Plot data--I'd like to be able to use line edit data here
ax.plot([1, 2, 3, 4], '*-')
# Refresh canvas
self.canvas.draw()
def stop(self):
print 'Stop Pressed'
if __name__ == "__main__":
import sys
app = QtGui.QApplication(sys.argv)
app.setApplicationName('MyWidget')
main = MyWidget()
main.show()
sys.exit(app.exec_())
MyDialog constructor has an attribute parent.
With the code bellow, you create an instance of MyDialog with MyWidget as a parent:
self.dialogTextBrowser = MyDialog(self)
Two ways for a widget to access data from it's parent:
Use the parent attribute in the __init__ function
self.lineEditData=parent.lineEdit.text()
Use the parent() method anywhere
def run(self):
self.lineEditData=self.parent().lineEdit.text()
I say it depends on how your suppose to use the application. If your suppose to fill the lineEdit once click and get a plot, I would use the parent attribute or directly pass the data in the __init__ function.
But if the user can go back to the lineEdit, change something, and click "run" again, then you should use the parent() method in run.
I am trying to make an android application...I am trying to switch from menu to server or client according to user input...but i am not able to switch from one class to another...main thing which pissed me off is that print statement inside ServerScreen is working but other part is not working...don't know why
Code:---
import kivy
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.uix.label import Label
from kivy.uix.button import Button
from kivy.uix.screenmanager import ScreenManager, Screen
class MenuScreen(Screen):
def __init__(self, **kwargs):
super(MenuScreen, self).__init__(**kwargs)
def Server(instance):
self.clear_widgets()
self.add_widget(Label ( text = 'Inside server function'))
server = ServerScreen()
#return server
#server.function()
self.add_widget(Label ( text = 'What Type Of Service You Want...???'))
button1 = Button(text = 'Server',size_hint = (None,None),pos = (0,0))
self.add_widget(button1)
button1.bind(on_press = Server)
button2 = Button(text = 'Client',size_hint = (None,None),pos = (100,0))
self.add_widget(button2)
#button2.bind(on_press = Client)
class ServerScreen(Screen):
def __init__(self, **kwargs):
super(ServerScreen, self).__init__(**kwargs)
print('Inside server screen')
self.clear_widgets()
self.add_widget(Label (text = 'Working As A Server'))
print("Hellooooooooooo")
sm = ScreenManager()
sm.add_widget(MenuScreen(name='Menu'))
sm.add_widget(ServerScreen(name='Server'))
#sm.add_widget(ClientScreen(name='Client'))
class FileApp(App):
def build(self):
#return Menu()
return sm
if __name__ == '__main__':
FileApp().run()
In which part i am making mistake...please point out that part & provide how can i solve that...
Output--->
Inside server screen
Hellooooooooooo
Look at my solution inspired by this excellent comment from inclement : Kivy: Changing screens in screen manager with an on_press event
import kivy
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.uix.label import Label
from kivy.uix.button import Button
from kivy.uix.screenmanager import ScreenManager, Screen
class MenuScreen(Screen):
def switching_function(*args):
global sm
sm.current = 'Server'
def __init__(self, **kwargs):
super(MenuScreen, self).__init__(**kwargs)
# def Server(instance):
# self.clear_widgets()
# self.add_widget(Label ( text = 'Inside server function'))
# server = ServerScreen()
# #return server
# #server.function()
self.add_widget(Label ( text = 'What Type Of Service You Want...???'))
button1 = Button(text = 'Server',size_hint = (None,None),pos = (0,0))
self.add_widget(button1)
# button1.bind(on_press = Server)
button1.bind(on_press = self.switching_function)
button2 = Button(text = 'Client',size_hint = (None,None),pos = (100,0))
self.add_widget(button2)
#button2.bind(on_press = Client)
class ServerScreen(Screen):
def __init__(self, **kwargs):
super(ServerScreen, self).__init__(**kwargs)
print('Inside server screen')
self.clear_widgets()
self.add_widget(Label (text = 'Working As A Server'))
print("Hellooooooooooo")
sm = ScreenManager()
sm.add_widget(MenuScreen(name='Menu'))
sm.add_widget(ServerScreen(name='Server'))
#sm.add_widget(ClientScreen(name='Client'))
class FileApp(App):
def build(self):
#return Menu()
return sm
The problem is with server = ServerScreen() inside
def Server(instance):
self.clear_widgets()
self.add_widget(Label ( text = 'Inside server function'))
server = ServerScreen()
#return server
#server.function()
It creates a new ServerScreen, not the ServerScreen which is actually displayed at the moment (so
Inside server screen
Hellooooooooooo
is displayed, but the ScreenManager has no idea that this additional Screen is existing.
I am currently learning how to work with the tkinter gui and I am trying to integrate with SQLAlchemy. The first hurdle was figuring out how to move between frames without destroying/closing the window, luckily I found this question: Switch between two frames in tkinter. So I used a lot of the provided code and created a simple application that is trying to have someone log in.
Now for the part I can't figure out. I have a function _check_credentials(self) deep inside the structure of windows that is trying to query the db. I have successfully created the table and queried it elsewhere.
I need to pass the session from the main.py module to the Login class and finally to the _check_credentials(self) method.
main.py -> Authorzation() -> Login() -> login_btn = tk.Button() -> _check_credentials()
Additional info:
I have included all of my code. Right now it runs, but crashes when the login button is pressed.
I have attempted to pass the session directly, ie. Authorzation(Session) but that crashes immediately.
Also, I am trying to follow the guidelines laid out in the sqlalchemy docs http://docs.sqlalchemy.org/en/latest/orm/session.html, FAQ, "When do I construct a Session, when do I commit it, and when do I close it?".
main.py:
from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
from module1 import Authorzation
import Tkinter as tk
Base = declarative_base()
engine = create_engine('sqlite:///:memory:', echo=True)
Base.metadata.create_all(engine)
Session = sessionmaker(bind=engine)
session = Session()
app = Authorzation()
app.mainloop()
module1.py:
import Tkinter as tk
import user
TITLE_FONT = ("Helvetica", 18, "bold")
class Authorzation(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
# the container is where we'll stack a bunch of frames
# on top of each other, then the one we want visible
# will be raised above the others
container = tk.Frame(self)
container.pack(side="top", fill="both", expand=True)
container.grid_rowconfigure(0, weight=1)
container.grid_columnconfigure(0, weight=1)
self.frames = {}
for F in (Login, Register):
frame = F(container, self)
self.frames[F] = frame
# put all of the pages in the same location;
# the one on the top of the stacking order
# will be the one that is visible.
frame.grid(row=0, column=0, sticky="nsew")
self.show_frame(Login)
def show_frame(self, c):
'''Show a frame for the given class'''
frame = self.frames[c]
frame.tkraise()
class Login(tk.Frame):
def __init__(self, parent, controller):
self.controller = controller
tk.Frame.__init__(self, parent)
label = tk.Label(self, text="Title", font=TITLE_FONT)
label.pack(side="top", fill="x", pady=10)
#Create the Username field
label_username = tk.Label(self, text="username")
label_username.pack()
self.username = tk.StringVar()
tk.Entry(self, textvariable=self.username).pack()
#Create the password field
label_password = tk.Label(self, text="password")
label_password.pack()
self.password = tk.StringVar()
tk.Entry(self, textvariable=self.password).pack()
login_btn = tk.Button(self, text="Login",
command=self._check_credentials)
login_btn.pack(pady=5)
reg_btn = tk.Button(self, text="Registration",
command=lambda: controller.show_frame(Register))
reg_btn.pack(pady=10)
def _check_credentials(self):
session_user = session.query(user.User)\
.filter_by(
username=self.username
).first()
if session_user:
return session_user.check_pwd(), session_user
else:
print("Sorry we could not find your username")
return False, None
self.controller.show_frame(Login)
class Register(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
label = tk.Label(self, text="This is page 1", font=TITLE_FONT)
label.pack(side="top", fill="x", pady=10)
button = tk.Button(self, text="Go to the start page",
command=lambda: controller.show_frame(Login))
button.pack()
After doing research on *args, and **kwargs. I realized I had not tried putting the session first in the __init__() function. Here is how I then passed the session to the controller.
main.py:
app = Authorzation(session)
module1.py
class Authorzation(tk.Tk):
def __init__(self, session, *args, **kwargs):
self.session = session
Once the session was in the controller it was easy to reference it from the Login() frame.
module1.py:
class Login(tk.Frame):
def __init__(self, parent, controller):
self.controller = controller
...
def _check_credentials(self):
session = self.controller.session
Note: this solution is also nice because it alleviates the need to pass the session through the button.