Difference between these two window structure? - python

Both of the code-snips below will create an empty Gtk window using python. However they seem quite different.
What is the main benefits of one vs the other ?
Is there any performance, security or compatibility implications of choosing one versus the other?
1st code-snip:
#!/usr/bin/python
from gi.repository import Gtk
win = Gtk.Window()
win.connect("delete-event", Gtk.main_quit)
win.show_all()
Gtk.main()
2nd code-snip:
from gi.repository import Gtk, GdkPixbuf, Gdk
import os, sys
class GUI:
def __init__(self):
window = Gtk.Window()
window.set_title ("Hello World")
window.connect_after('destroy', self.destroy)
window.show_all()
def destroy(self, window):
Gtk.main_quit()
def main():
app = GUI()
Gtk.main()
if __name__ == "__main__":
sys.exit(main())
Ref1: 1st snip-code reference
Ref2: 2nd snip-code reference

The second snippet is more object-oriented, it defines a class GUI that you can extend for your application, which is a more elegant solution in my opinion. Additionally, it properly defines a main() function and calls it, this gives you more flexibility and allows you to import this module from elsewhere without instantiating the GUI on import. There are, as you asked, no real performance, compatibility or security implications.
In the 2nd snippet, I would, however, bind the window to self (self.window = Gtk.Window()), allowing you access from any method in the class.

Related

Python Gtk 3 window is not defined, class instancing confusion

I am just starting to get into python and I am utterly confused as to how object creation works. I am trying to create user interface with GTK. Here is an example of the problem I am having:
from gi.repository import Gtk
def button_clicked(self, button):
self.button_label = button.get_label()
if self.button_label == "Login":
window.quit()
window2.start()
class LoginWindow(Gtk.Window):
def __init__(self):
Gtk.Window.__init__(self, title="AMOK Cloud")
self.connect("delete-event", Gtk.main_quit)
self.set_position(position = Gtk.WindowPosition.CENTER)
# Button
self.loginbutton = Gtk.Button(label="Login")
self.loginbutton.connect("clicked", button_clicked(self, self.loginbutton))
self.add(self.loginbutton)
self.show_all()
Gtk.main()
def quit(self):
self.close()
Gtk.main_quit()
class MainWindow(Gtk.Window):
def __init__(self):
Gtk.Window.__init__(self, title="AMOK Cloud")
self.connect("delete-event", Gtk.main_quit)
self.set_position(position=Gtk.WindowPosition.CENTER)
def start(self):
self.show_all()
Gtk.main()
window = LoginWindow()
window2 = MainWindow()
Error comes up as NameError: name 'window' is not defined
even though I did define window. I don't understand. If someone can explain it would mean the world to me. Thanks in advance.
EDIT:
Thanks guys this works fine now, took Gtk.main() out of both classes and added button_clicked method inside LoginWindow() class and now it works like a charm. I assumed I needed Gtk.main() for every window I open.
It is because you are starting the main loop (Gtk.main()) inside of LoginWindow.__init__(). That means that the window = LoginWindow() line doesn't finish executing until after the login window is closed. You should take Gtk.main() outside of the __init__ method, and move it to the last line in the file. As mentioned by PM 2Ring in the comments, you don't need to call Gtk.main() twice. Take it out completely in MainWindow.start() because the one now added to the last line in the file takes care of that. Also mentioned by PM, connect() calls a function when an event happens. When you give it button_clicked(...), that function is called and you are actually telling connect() to call whatever is returned, None. If you want special arguments, use a lambda, but you aren't even changing anything (those are the default arguments anyway), so you can simply do this:
self.connect("clicked", button_clicked)
I would also suggest that instead of making button_clicked a separate function, make it a static method of the class. You do that by placing it inside the class, but with #staticmethod just above the def line. That way, it makes sense for it to take the self argument, but you don't need two parameters to account for the same window.

Multiple application/file/windows instances running on tkinter

Here is a sample situation:
I have written a tk GUI that opens and edits e.g. .txt files. I'm currently on a mac, but I might also want to run this on windows. Currently the main Application class creates its own internal tk.Tk() like so
import tkinter as tk
class App:
def __init__(self):
self.root = tk.Tk()
tk.Label(master=self.root,text="content").pack()
if __name__ == '__main__':
a=App()
a.root.mainloop()
I want to add multi file capabilities to the application. In the current system this would result in 2 tk.Tk() instances running which I couldn't get to work and people say is unpredictable.
I want to be able to close any of the multiple files and still have the application running until the last window is closed and then the application quit or stays without a window (like on a mac).
My problem is that if I use tk.Toplevel() for each of my windows I have a ugly default tk.Tk() window which I would need to hide which seams inelegant. It would also be messy to determine which file is currently in focus for actions with the menubar.
I'm also considering each file being it's own application instance like on Windows, but that would fill the dock with repeated icons and be inconsistent with the rest of the system.
Here are the possible way I came up with:
Multiple Tks (Works but more complex examples are unpredictable):
import tkinter as tk
class App:
def __init__(self):
self.root = tk.Tk()
tk.Label(master=self.root,text="content").pack()
tk.Button(master=self.root,text="new_window",command=self.open).pack()
def open(self):
App()
if __name__ == '__main__':
a=App()
a.root.mainloop()
Hidden tk window and multiple Toplevels (Needs hiding the Tk and the osx menubar commands like view->change_colors would need to manaly decide where to direct comands):
import tkinter as tk
class App:
def __init__(self):
self.root = tk.Toplevel()
tk.Label(master=self.root,text="content").pack()
tk.Button(master=self.root,text="new_window",command=self.open).pack()
def open(self):
App()
if __name__ == '__main__':
tk.Tk()
a=App()
a.root.mainloop()
Each Window is its own Application and fully independant (Dosn't fit in with the other mac applications, the implementation is ugly):
#!/usr/local/bin/python3
import tkinter as tk
import sys,os
class App:
def __init__(self):
self.root = tk.Tk()
tk.Label(master=self.root,text="content").pack()
tk.Button(master=self.root,text="new_window",command=self.open).pack()
def open(self):
os.system(sys.argv[0]+"&")
if __name__ == '__main__':
a=App()
a.root.mainloop()
I was alos think of maybe doing it with threads but I think I must be over thinking it so I came here.
Is there a generally accepted way of doing this in tk?
The generally accepted way is just like you describe: use Toplevel for additional windows, and hide the root window if you don't want to see it.
Another choice is to make your main program a non-GYI app, and each window is created by spawning a new process.
Hidden tk window and multyple Toplevels (Needs hiding the Tk and the osx menubar commands like view->change_colors would need to manaly decide where to direct comands):
It is easy to get into "which goes with what" hell with multiple Toplevels. Instead create a separate class for each new Toplevel with built in responses to button clicks, etc. Pass "root" to the class and let it create, update, and destroy as necessary, and keep track of it's own variables. If you want to use variables elsewhere, then store the class instance when the Toplevel classes are called and create the variables within the class as instance attributes.

accessing QtGui objects created by pyQt

So I'm quit new to working with UI in python. I'm not really grasping a core concept and i think this simple question will help flip on the light switch.
As seen in the code snippet below, I imported a ui file made in Qt. This ui has a pushbutton on it. How do I make a click event on that button? I have gone through tutorials on how to code a button and use it. I understand that. It is the question of how to access the objects and manipulate the objects that are created by the ui file. What i really want to do is see how to perform a function (or instantiate a class or whatever) when a button is clicked. that function being one that i wrote. baby steps though. any answers and elaborations would be appreciated.
import sys
from PyQt4 import QtGui, uic, QtCore
class MyWindow(QtGui.QMainWindow):
def __init__(self):
super(MyWindow, self).__init__()
uic.loadUi('myWidget.ui', self)
self.show()
if __name__ == '__main__':
app = QtGui.QApplication(sys.argv)
window = MyWindow()
sys.exit(app.exec_())
like i said. very simple question but I'm just not really grasping the core concept here. thanks you.
self.ui=uic.loadUi('curveViewer.ui', self)
#where `your_pushbutton` is the button name specified in your .ui file:
self.ui.your_pushbutton.clicked.connect(self.onBtnClicked)
or just:
uic.loadUi('curveViewer.ui', self)
self.your_pushbutton.clicked.connect(self.onBtnClicked)
then define method onBtnClicked inside your class MyWindow:
def onBtnClicked():
print 'pushbutton clicked'
see New-style Signal and Slot Support
btw, it's better to remove self.show(), and make it:
window = MyWindow()
window.show()

QWidget showFullScreen produces multiple resizeEvents

I have a QT application written in python using PySide and I stumbled across a little problem regarding the showFullScreen method of the QGLWidget (although the problem occurs with every other widget too):
The problem is, that the widget doesn't have its 'final' resolution after the program returns from showFullScreen.
The switch seems to be triggered asynchronously between 5 and 10 milliseconds later.
This is a problem for me because I have to do some layout calculations which depend on the widget's size after it is shown.
Below is a little reproducer which subclasses QGLWidget. Using this reproducer you will take notice, that resizeEvent will be called twice after showFullScreen.
I'm looking for a convinient way of knowing which resizeEvent is the 'final' one, or a way of knowing, when the widget really is in fullscreen mode. Is there maybe any signals I could connect to?
Thanks a lot for any help on this.
#!/usr/bin/python
import sys
from PySide.QtGui import QApplication
from PySide.QtCore import QTimer
from PySide.QtOpenGL import QGLWidget
class TestWidget(QGLWidget):
def __init__(self, parent=None):
super(TestWidget, self).__init__(parent)
self._timer = QTimer()
self._timer.setInterval(5)
self._timer.timeout.connect(self.showsize)
self._timer.start()
def resizeEvent(self, event):
print "Resize event:", event.size().width(), event.size().height()
def showsize(self):
w = widget.size().width()
print "Timer: ", w, widget.size().height()
if w == 1680:
self._timer.stop()
if __name__ == "__main__":
app = QApplication(sys.argv)
widget = TestWidget()
widget.showFullScreen()
print "After showFullScreen:", widget.size().width(), widget.size().height()
# this will always be 640 480...1680 1050 is what I'm expecting
app.exec_()
One possibility is to check that if the resize event is spontaneous or not. From limited testing here (using Qt C++ on Linux), the second resize event is spontaneous, while the first one is not.
You could do your calculations only when the event is spontaneous.
Note: I'm not sure how portable this is, it might depend on your window manager/windowing system.

Undo with GTK TextView

I'm trying to keep dependencies to a minimum for a program I contribute to, it's a small text editor.
GTK Textview doesn't seem to come with a built-in undo function. Is there any reference implementation I've been missing on so far? Is everyone writing their own undo function for their TextView widgets?
I'll be happy about any sample code - most happy about python sample code, as our project is in python.
as a follwow-up: I ported gtksourceview's undo mechanism to python: http://bitbucket.org/tiax/gtk-textbuffer-with-undo/
serves as a drop-in replacement for gtksourceview's undo
(OP here, but launchpad open-id doesn't work anymore)
As far as I know, GTK TextView doesn't include an undo function. So while I am not familiar with Python's GTK library, I would think it doesn't have one.
The Ruby-GNOME2 project has a sample text editor that has undo/redo functionality. Basically they are connecting to the insert_text and delete_range signals of the TextView widget and recording the events and associated data in a list.
Depending on just how dependency-averse you are, and what kind of text editor you're building, GtkSourceView adds undo/redo among many other things. Very worth looking at if you want some of the other features it offers.
Use GtkSource
https://wiki.gnome.org/Projects/GtkSourceView
https://lazka.github.io/pgi-docs/GtkSource-3.0/
https://lazka.github.io/pgi-docs/GtkSource-3.0/classes.html
.
[Cmnd] + [Z] for undo (default)
[Cmnd] + [Shift] + [Z] for redo (default)
[Cmnd] + [Y] for redo (added manually)
example:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
from gi.repository import Gdk
gi.require_version('GtkSource', '3.0')
from gi.repository import GtkSource
import os
class TreeviewWindow(Gtk.Window):
def __init__(self):
Gtk.Window.__init__(self, title="TreeviewWindow")
self.set_size_request(300, 300)
self.connect("key-press-event", self._key_press_event)
self.mainbox = Gtk.VBox(spacing=10)
self.add(self.mainbox)
self.textbuffer = GtkSource.Buffer()
textview = GtkSource.View(buffer=self.textbuffer)
textview.set_editable(True)
textview.set_cursor_visible(True)
textview.set_show_line_numbers(True)
self.mainbox.pack_start(textview, True, True, 0)
self.show_all()
def _key_press_event(self, widget, event):
keyval_name = Gdk.keyval_name(event.keyval)
ctrl = (event.state & Gdk.ModifierType.CONTROL_MASK)
if ctrl and keyval_name == 'y':
if self.textbuffer.can_redo():
self.textbuffer.do_redo(self.textbuffer)
def main(self):
Gtk.main()
if __name__ == "__main__":
base = TreeviewWindow()
base.main()

Categories

Resources