I am a beginner when it gomes to GUI programming with Python so I am guessing my problem has a simple solution even if I have not found a solution searching with google, wikis, documentation, examples ...
What I am trying to achive is that a value in an entry widget should constantly increase up to a max value as long as a button is pressed.
I have tried using callback for the event "button-press-event" but get the same response as with callback for the signal "clicked".
When connecting to "clicked" the application works as expected, e.g. the value is incremented each click but when I use a connection to the event "button-press-event" I still only get increment for each click (press and release)
I am using this with Python3.2 (on a Raspberry Pi 2)
Below is the working code that acts on each click:
#!/usr/bin/python
from gi.repository import Gtk, Gdk
from time import sleep
class MyWindow(Gtk.Window):
def __init__(self):
Gtk.Window.__init__(self, title="ST")
MAX_SPD = 3000
self.set_default_size(100,100)
self.set_size_request(100,100)
self.set_resizable(False)
spdEntry = Gtk.Entry()
spdEntry.set_has_frame(True)
spdEntry.set_text("0")
spdEntry.connect("activate", self.inputSpd, MAX_SPD)
start = Gtk.Button("Start")
start.connect("clicked", self.clicked_start)
stop = Gtk.Button("Stop")
stop.connect("clicked", self.clicked_stop)
inc = Gtk.Button("inc")
inc.connect("clicked", self.pressed_inc, spdEntry, MAX_SPD)
fixed = Gtk.Fixed()
fixed.put(start, 0, 0)
fixed.put(spdEntry, 0, 40)
fixed.put(stop, 0, 70)
fixed.put(inc, 120, 0)
self.add(fixed)
def clicked_start(self, widget):
self.set_title("GO")
def clicked_stop(self, widget):
self.set_title("ST")
def pressed_inc(self, widget, entry, maxSpd):
speed = int(entry.get_text())
speed = speed+1
if speed > maxSpd:
speed = maxSpd
entry.set_text(str(speed))
def inputSpd(self, entry, maxSpd):
speed = int(entry.get_text())
if speed > maxSpd:
speed = maxSpd
entry.set_text(str(speed))
win = MyWindow()
win.connect("delete-event", Gtk.main_quit)
win.show_all()
Gtk.main()
This is the non working code that should increment as long button is pressed:
#!/usr/bin/python
from gi.repository import Gtk, Gdk
from time import sleep
class MyWindow(Gtk.Window):
def __init__(self):
Gtk.Window.__init__(self, title="ST")
MAX_SPD = 3000
self.set_default_size(100,100)
self.set_size_request(100,100)
self.set_resizable(False)
spdEntry = Gtk.Entry()
spdEntry.set_has_frame(True)
spdEntry.set_text("0")
spdEntry.connect("activate", self.inputSpd, MAX_SPD)
start = Gtk.Button("Start")
start.connect("clicked", self.clicked_start)
stop = Gtk.Button("Stop")
stop.connect("clicked", self.clicked_stop)
inc = Gtk.Button("inc")
inc.connect("button-press-event", self.pressed_inc, spdEntry, MAX_SPD)
inc.connect("button-release-event", self.left_inc)
fixed = Gtk.Fixed()
fixed.put(start, 0, 0)
fixed.put(spdEntry, 0, 40)
fixed.put(stop, 0, 70)
fixed.put(inc, 120, 0)
self.add(fixed)
def clicked_start(self, widget):
self.set_title("GO")
def clicked_stop(self, widget):
self.set_title("ST")
def pressed_inc(self, widget, event, entry, maxSpd):
if event.type == Gdk.EventType.BUTTON_PRESS:
speed = int(entry.get_text())
speed = speed+1
if speed > maxSpd:
speed = maxSpd
entry.set_text(str(speed))
return True
def left_inc(self, widget, event):
if event.type == Gdk.EventType.BUTTON_RELEASE:
return True
def inputSpd(self, entry, maxSpd):
speed = int(entry.get_text())
if speed > maxSpd:
speed = maxSpd
entry.set_text(str(speed))
win = MyWindow()
win.connect("delete-event", Gtk.main_quit)
win.show_all()
Gtk.main()
You can do this by using GLib.timeout_add(). However, I agree to gianmt that it is better to just use a Gtk.SpinButton
#!/usr/bin/python
from gi.repository import Gtk, Gdk, GLib
class MyWindow(Gtk.Window):
def __init__(self):
Gtk.Window.__init__(self, title="ST")
self.MAXSPEED = 3000
self.set_default_size(100,100)
self.set_resizable(False)
self.entry = Gtk.Entry()
self.entry.set_text("0")
start = Gtk.Button(label="Start")
start.connect("clicked", self.clicked_start)
stop = Gtk.Button(label="Stop")
stop.connect("clicked", self.clicked_stop)
inc = Gtk.Button(label="inc")
inc.connect("button-press-event", self.pressed_inc)
inc.connect("button-release-event", self.left_inc)
fixed = Gtk.Fixed()
fixed.put(start, 0, 0)
fixed.put(self.entry, 0, 40)
fixed.put(stop, 0, 70)
fixed.put(inc, 120, 0)
self.add(fixed)
def clicked_start(self, widget):
self.set_title("GO")
def clicked_stop(self, widget):
self.set_title("ST")
def pressed_inc(self, widget, event):
self.inc_id = GLib.timeout_add(100, self.increase)
def left_inc(self, widget, event,):
GLib.source_remove(self.inc_id)
def increase(self):
speed = int(self.entry.get_text()) + 1
if speed > self.MAXSPEED:
self.entry.set_text(str(self.MAXSPEED))
else:
self.entry.set_text(str(speed))
return True
win = MyWindow()
win.connect("delete-event", Gtk.main_quit)
win.show_all()
Gtk.main()
There was also a from time import sleep as an import on top of your code. It was not used and I do not know about the rest of your application but using time.sleep(), while you are not in a thread, will block the Gtk.main() loop and make your application unresponsive.
Related
Today I am trying to develop an UI using cefpython which allows me to embed a web browser and interacts with it with javascript bindings.
I'm using it to develop on Windows platform.
For this purpose, I am using the "multi_threaded_message_loop" flag which allows me to gain in performance.
I'm also using wxpython on python 3 to embed it.
The problem is when I resize my window, the use of WindowUtils.OnSize() freezes my app. 99% of the time, it happens when the browser is loading (but it also happens when it's done (rarely)).
Here is a sample code to reproduce :
import platform
import sys
import wx
from cefpython3 import cefpython
WindowUtils = cefpython.WindowUtils()
WIDTH = 800
HEIGHT = 600
import os
class MainFrame(wx.Frame):
browser = None
mainPanel = None
def createMainBrowser(self):
self.browser = self.createBrowser(self.mainPanel)
def createBrowser(self, parent):
browser = cefpython.CreateBrowserSync(
self.getWindowInfo(parent),
browserSettings={},
navigateUrl='http://www.google.com'
)
return browser
def getWindowInfo(self, parent):
windowInfo = cefpython.WindowInfo()
windowInfo.SetAsChild(parent.GetHandle(), [0, 0, WIDTH, HEIGHT])
return windowInfo
def __init__(self):
wx.Frame.__init__(
self, parent=None, id=wx.ID_ANY, title='wx', size=(WIDTH, HEIGHT)
)
self.mainPanel = wx.Panel(self)
self.mainPanel.SetBackgroundColour(wx.GREEN)
cefpython.PostTask(cefpython.TID_UI, self.createMainBrowser)
self.mainPanel.Bind(wx.EVT_SIZE, self.OnSize)
def OnSize(self, _):
if not self.browser:
return
WindowUtils.OnSize(self.mainPanel.GetHandle(), 0, 0, 0)
self.browser.NotifyMoveOrResizeStarted()
class App(wx.App):
def OnInit(self):
frame = MainFrame()
frame.Show()
return True
if __name__ == '__main__':
sys.excepthook = cefpython.ExceptHook # To shutdown all CEF processes on error
cefpython.Initialize({
"locales_dir_path": cefpython.GetModuleDirectory() + "/locales",
"browser_subprocess_path": cefpython.GetModuleDirectory() + "/subprocess",
"auto_zooming": "system_dpi",
"multi_threaded_message_loop": True,
})
app = App(False)
app.MainLoop()
cefpython.Shutdown()
Thank you a lot for your help !
Alann
Problem solved !
Instead of using
def OnSize(self, _):
if not self.browser:
return
WindowUtils.OnSize(self.mainPanel.GetHandle(), 0, 0, 0)
self.browser.NotifyMoveOrResizeStarted()
I use
def OnSize(self, sizeEvent):
if not self.browser:
return
w = sizeEvent.GetSize().GetWidth()
h = sizeEvent.GetSize().GetHeight()
win32gui.SetWindowPos(self.browser.GetWindowHandle(), 0, 0, 0, w, h, 0)
self.browser.NotifyMoveOrResizeStarted()
I don't know if this is because I'm on windows 10 but maybe WindowsUtils needs to be updated !
I would like to let the user of my application draw something. Which signal / event do I use for that?
This is what I've got so far:
#!/usr/bin/env python
import gtk
class DrawingAreaExample:
def __init__(self):
window = gtk.Window(gtk.WINDOW_TOPLEVEL)
window.set_title("Drawing Area Example")
window.set_default_size(800, 600)
window.connect('button-press-event', self.callback)
window.connect("destroy", lambda w: gtk.main_quit())
self.area = gtk.DrawingArea()
self.area.set_size_request(400, 300)
self.pangolayout = self.area.create_pango_layout("")
self.sw = gtk.ScrolledWindow()
self.sw.add_with_viewport(self.area)
self.table = gtk.Table(2, 2)
self.table.attach(self.sw, 1, 2, 1, 2)
window.add(self.table)
self.area.connect("expose-event", self.area_expose_cb)
self.area.show()
self.sw.show()
self.table.show()
window.show()
def callback(self, window, event):
self.draw_point(int(event.x), int(event.y))
def area_expose_cb(self, area, event):
self.style = self.area.get_style()
self.gc = self.style.fg_gc[gtk.STATE_NORMAL]
return True
def draw_point(self, x, y):
# self.area.window.draw_point(self.gc, x, y)
self.area.window.draw_arc(self.gc, True, x, y, 5, 5, 5, 360*64)
def main():
gtk.main()
return 0
if __name__ == "__main__":
DrawingAreaExample()
main()
I just got it to work. Thanks to http://zetcode.com/gfx/pycairo/basicdrawing/ for the tutorial which helped me a lot!
#!/usr/bin/python
"""Write on a canvas, store on-line data."""
from gi.repository import Gtk, Gdk
import time
import math
__version__ = '0.1'
class FormulaWriter(Gtk.Window):
def __init__(self):
super(FormulaWriter, self).__init__()
self.odata = [] # On-line writing information, grouped by strokes
# General properties
self.set_title("Formula Writer %s" % __version__)
self.resize(400, 400)
self.set_position(Gtk.WindowPosition.CENTER)
self.connect("delete-event", Gtk.main_quit)
# Set up canvas
self.canvas = Gtk.DrawingArea()
self.canvas.connect("draw", self.on_draw)
self.canvas.connect("button-press-event", self.on_button_press)
self.canvas.connect("motion-notify-event", self.on_mouse_move)
self.canvas.connect("motion-notify-event", self.on_mouse_move)
self.canvas.set_events(self.canvas.get_events() |
Gdk.EventMask.BUTTON_MOTION_MASK |
Gdk.EventMask.BUTTON1_MOTION_MASK |
Gdk.EventMask.BUTTON2_MOTION_MASK |
Gdk.EventMask.BUTTON3_MOTION_MASK |
Gdk.EventMask.BUTTON_PRESS_MASK)
self.add(self.canvas)
self.show_all()
def on_button_press(self, w, event):
"""When a button is pressed, the location gets stored and the canvas
gets updated.
"""
self.odata.append([{'x': event.x, 'y': event.y, 'time': time.time()}])
self.canvas.queue_draw()
def on_mouse_move(self, w, event):
"""When mouse is moved, the mouse position gets stored."""
point = {'x': event.x, 'y': event.y, 'time': time.time()}
self.odata[-1].append(point)
self.canvas.queue_draw()
def on_draw(self, wid, cr):
"""Handler for drawing action. Draw all strokes.
:param wid: The DrawingArea
:param cr: Context
"""
cr.set_source_rgb(1, 0, 0) # All strokes get drawn in red
cr.set_line_width(2.5)
for stroke in self.odata:
for i, point in enumerate(stroke):
if len(stroke) == 1:
radius = 2
cr.arc(point['x'], point['y'], radius, 0, 2.0*math.pi)
cr.fill()
cr.stroke()
elif i != 0:
cr.move_to(stroke[i-1]['x'], stroke[i-1]['y'])
cr.line_to(point['x'], point['y'])
cr.stroke()
def main():
FormulaWriter()
Gtk.main()
if __name__ == "__main__":
main()
button-press-event is correct, but you want to hook it up to the GtkDrawingArea, not to the GtkWindow. You'll also need motion-notify-event to handle mouse moves during the button press.
The tutorial here will show you how to do what you want to do. There are a few other slight problems with your code (such as the use of expose-event instead of draw) that this code should show how to do right. Unfortunately it's in C; IDK if the Python GTK+ 3 tutorial has the same example.
i am very new to python. I want to open a Python GTK Window which should display a moving text just like a marquee in HTML. Kindly anyone suggest a solution
i am using this piece of code:
#!/usr/bin/env python
import pygtk
pygtk.require('2.0')
import gtk
class MyProgram:
def __init__(self):
# create a new window
app_window = gtk.Window(gtk.WINDOW_TOPLEVEL)
app_window.set_size_request(800, 350)
app_window.set_border_width(15)
app_window.set_title("Volks Electronics")
app_window.connect("delete_event", lambda w,e: gtk.main_quit())
vbox_app = gtk.VBox(False, 0)
app_window.add(vbox_app)
vbox_app.show()
label_app = gtk.Label("Sample Page ")
label_app.show()
vbox_app.pack_start(label_app, False, False, 1)
# Draw Table() to layout text:
table_layout = gtk.Table(rows=5, columns=5, homogeneous=True)
label_a = gtk.Label("Train Name:")
label_a.show()
table_layout.attach(label_a, 0, 1, 0, 1, 0,0,0,0)
label_c = gtk.Label("Train No:")
label_c.show()
table_layout.attach(label_c, 0, 1, 2, 3, 0,0,0,0)
label_d = gtk.Label("Departed From:")
label_d.show()
table_layout.attach(label_d, 0, 1, 3, 4, 0,0,0,0)
label_b = gtk.Label("Next Station:")
label_b.show()
table_layout.attach(label_b, 0, 1, 1, 2, 0,0,0,0)
table_layout.show()
vbox_app.add(table_layout)
# Use HBox() to layout text and button next to each other:
hbox_close = gtk.HBox(False, 0)
label_close = gtk.Label("Close aplication: ")
hbox_close.pack_start(label_close, True, True, 0)
label_close.show()
button_close = gtk.Button(stock=gtk.STOCK_CLOSE)
button_close.connect("clicked", lambda w: gtk.main_quit())
button_close.set_flags(gtk.CAN_DEFAULT)
hbox_close.pack_start(button_close, True, True, 0)
button_close.show()
hbox_close.show()
vbox_app.add(hbox_close)
# Place after association to hbox/vbox to avoid the following error:
# GtkWarning: gtkwidget.c:5460: widget not within a GtkWindow
button_close.grab_default()
app_window.show()
return
def main():
gtk.main()
return 0
if __name__ == "__main__":
MyProgram()
main()
I want to put some text after that close button which should work like a moving banner(marquee in HTML). I couldn't find any code which works like a marquee in a GTK window. Please suggest any way to do this
I like this.
#!/usr/bin/python
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk, GObject
class MyWindow(Gtk.Window):
def __init__(self):
Gtk.Window.__init__(self, title="Hello World")
self.box = Gtk.Box(spacing=6)
self.add(self.box)
self.label = Gtk.Label()
self.box.pack_start(self.label, True, True, 0)
self.gibberish = "Spam and eggs, spam and eggs, spam and eggs!"
self.a = 0
self.z = 40
def marquee(self, text):
if self.a < len(text):
self.a = self.a + 1
self.z = self.z + 1
if self.a >= len(text):
self.a = 0
self.z = 40
return str(text[self.a:self.z])
# Displays Marquee
def displayMarquee(self):
# putting our text into our function and setting our label to the result.
# we need to return "True" to ensure the timer continues to run, otherwise it will only run once.
self.label.set_label(self.marquee(self.gibberish))
return True
# Initialize Marquee
def startMarquee(self):
# this takes 2 args: (how often to update in millisec, the method to run)
GObject.timeout_add(500, self.displayMarquee)
win = MyWindow()
win.connect("destroy", Gtk.main_quit)
win.show_all()
win.startMarquee()
Gtk.main()
I'd like to get the current background color of my textview to change it and restore it later.
here what I tried:
context = textview.get_style_context()
state = Gtk.StateFlags.NORMAL
color = context.get_background_color(state)
I tried all possible states, but none returns the correct background color (white in my case)
Any idea how to get it?
I'm not exactly sure what you specific problem is without seeing more code, but here is a quick example that overrides the background and then restores it on a button click:
from gi.repository import Gtk, Gdk
import sys
class MyWindow(Gtk.ApplicationWindow):
def __init__(self, app):
Gtk.Window.__init__(self, title="Textview example", application=app)
self.set_default_size(250, 100)
self.set_border_width(10)
self.view = Gtk.TextView()
self.style_context = self.view.get_style_context()
self.default_bg_color = self.style_context.get_background_color(Gtk.StateFlags.NORMAL)
self.view.override_background_color(Gtk.StateFlags.NORMAL,
Gdk.RGBA(0, 0, 0, 1))
self.btn = Gtk.Button(label="Click Here")
self.btn.connect("clicked", self.on_btn_clicked)
box = Gtk.VBox()
box.pack_start(self.view, True, True, 0)
box.pack_start(self.btn, False, False, 0)
self.add(box)
def on_btn_clicked(self, widget):
current_bg = self.style_context.get_background_color(Gtk.StateFlags.NORMAL)
if current_bg == self.default_bg_color:
self.view.override_background_color(Gtk.StateFlags.NORMAL,
Gdk.RGBA(0, 0, 0, 1))
else:
self.view.override_background_color(Gtk.StateFlags.NORMAL,
self.default_bg_color)
class MyApplication(Gtk.Application):
def __init__(self):
Gtk.Application.__init__(self)
def do_activate(self):
win = MyWindow(self)
win.show_all()
def do_startup(self):
Gtk.Application.do_startup(self)
app = MyApplication()
exit_status = app.run(sys.argv)
sys.exit(exit_status)
Can somebody provide a code snippet that can be used under Gtk3 to change the cursor to a hour glass using python..?
The following Window implementation does that:
import time
from gi.repository import Gdk, Gtk, GObject
class MainWindow(Gtk.Window):
"""Example window."""
def __init__(self):
"""Create new instance."""
super(MainWindow, self).__init__()
self.set_title('Test Windows')
box = Gtk.VBox()
label = Gtk.Label("Just a label....")
box.pack_start(label, True, True, 0)
button = Gtk.Button(" and a button")
box.pack_start(button, True, True, 0)
self.add(box)
self.connect("destroy", Gtk.main_quit)
self.show_all()
def set_watch(self):
"""Set the mouse to be a watch."""
watch = Gdk.Cursor(Gdk.CursorType.WATCH)
gdk_window = self.get_root_window()
gdk_window.set_cursor(watch)
def long_call(self):
"""Perform a long call."""
time.sleep(10) # your time consuming operation here
arrow = Gdk.Cursor(Gdk.CursorType.ARROW)
gdk_window = self.get_root_window()
gdk_window.set_cursor(arrow)
window = MainWindow()
window.set_watch()
GObject.idle_add(window.long_call)
Gtk.main()
It is important that you do set the pointer to be a watch OUTSIDE the idel_add call otherwise it won't be set.