I can't get double clicking to work on a Surface Pro 3 (Fedora; Kernel 4.28; Gnome 3.18, Gtk3). Two fast consecutive taps are not converted to a 2button event in Gtk+. See the small Python program below, which works fine for a normal mouse or touch pad.
I've checked that it is not a problem with the tap time and not the tap distance as you can see in the program. Where could this problem originate from? GDK_TOUCH_MASK?
To clarify, button events are received, but never converted to 2button event
#!/usr/bin/python
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk, Gdk, GLib
class MyWindow(Gtk.Window):
def __init__(self):
Gtk.Window.__init__(self, title="Double Click Test")
self.button = Gtk.Button.new_with_label("Double-click test\n\n")
self.button.connect("button-press-event", self.test_button_clicked)
self.button.connect("button-release-event", self.test_button_released)
settings = Gtk.Settings.get_default()
Gtk.Settings.set_property(settings,'gtk-double-click-distance',1000)
print Gtk.Settings.get_property(settings,'gtk-double-click-distance')
Gtk.Settings.set_property(settings,'gtk-double-click-time',1000)
print Gtk.Settings.get_property(settings,'gtk-double-click-time')
self.add(self.button)
def test_button_clicked(self, widget, event):
if event.type == Gdk.EventType._2BUTTON_PRESS:
widget.set_label(("Success!"))
GLib.timeout_add(1000, self.reset_test_button, widget)
return True
def test_button_released(self, widget, event):
return True
def reset_test_button(self, widget):
widget.set_label(("Double-click test"))
return False
win = MyWindow()
win.connect("delete-event", Gtk.main_quit)
win.show_all()
Gtk.main()
Related
I'm new to GTK programming. I want to have a Label widget whose text can be edited, kind of like this: https://docs.gtk.org/gtk4/class.EditableLabel.html.
The problem is I have no idea how to implement this. I understand that Gtk.Button has a set_label() function, though I don't know how to use it to make an editable label.
You can do that with Gtk.Entry which you can set_editable based on "something". Example with check button would look something like this:
import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk
def on_editable_toggled(button, entry):
value = button.get_active()
entry.set_editable(value)
entry.set_sensitive(value)
win = Gtk.Window()
win.connect("destroy", Gtk.main_quit)
vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=6)
win.add(vbox)
entry = Gtk.Entry()
entry.set_text("Hello World")
vbox.pack_start(entry, True, True, 0)
check_editable = Gtk.CheckButton(label="Editable")
check_editable.connect("toggled", on_editable_toggled, entry)
check_editable.set_active(True)
vbox.pack_start(check_editable, True, True, 0)
win.show_all()
Gtk.main()
It doesn't really look like a label, but you can use the Gtk CSS styling to change the background and border colors to make it look like one when it is set to non-editable.
from kivy.app import App
from kivy.uix.gridlayout import GridLayout
from kivy.uix.label import Label
from kivy.uix.textinput import TextInput
from kivy.uix.button import Button
class LoginScreen(GridLayout):
def __init__(self, **kwargs):
super(LoginScreen, self).__init__(**kwargs)
self.cols = 2
self.submit = Button(text='Order', font_size=40)
self.add_widget(self.submit)
self.submit.bind(on_press=self.pressed)
def pressed(self, instance):
pressing = Secondtab()
pressing()
class Secondtab(GridLayout):
def __init__(self, **kwargs):
super(Secondtab, self).__init__(**kwargs)
self.cols = 5
self.submit = Button(text='Drinks', font_size=40)
self.add_widget(self.submit)
print('check')
def __call__(self):
print('new tab')
class MyApp(App):
def build(self):
return LoginScreen()
if __name__ == '__main__':
MyApp().run()
So I want the window to change to a new layout when I press the first button. I tought making a new grid class and calling it would work but it didnt work as I expected. I dont want the button to open a new window tho I want the current window to refresh to the new layout.
As #John Anderson suggested. Take a look at the screen manager widget. The 'current window' must be a populated screen widget and you could change the current screen by assigning the next screen's name to the current attribute.
This will help you I guess. Using ScreenManager:
from kivy.uix.screenmanager import ScreenManager, Screen, SlideTransition
class LoginScreen(GridLayout):
def __init__(self, **kwargs):
super(LoginScreen, self).__init__(**kwargs)
self.cols = 2
self.submit = Button(text='Order', font_size=40)
self.add_widget(self.submit)
self.submit.bind(on_press=self.pressed)
def pressed(self, instance):
pressing = Secondtab()
pressing()
myapp.screen_manager.transition = SlideTransition(direction='left', duration=.25) #You can change transition speed or you could just remove it to set it on default
myapp.screen_manager.current = 'Secondtab'
class MyApp(App):
def build(self):
return LoginScreen()
self.screen_manager = ScreenManager()
self.loginscreen = LoginScreen()
screen = Screen(name='LoginScreen')
screen.add_widget(self.loginscreen)
self.screen_manager.add_widget(screen)
self.secondtab = Secondtab()
screen = Screen(name='Secondtab')
screen.add_widget(self.secondtab)
self.screen_manager.add_widget(screen)
return self.screen_manager
I have a button that runs a loop and updates the window accordingly. I want another "pause" button that pauses this loop but it doesn't seem like I can do that while the loop is running. Perhaps threading is the solution (I tried GLib.timeout_add_seconds without success) - what is the easiest way to make this work?
I have attached my faulty code:
import sys
from time import sleep
import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk
class LoopButton(Gtk.Box):
def __init__(self, GUI):
Gtk.Box.__init__(self)
self.GUI = GUI
self.set_border_width(10)
self.message = "1"
button = Gtk.Button.new_with_label("Run")
button.connect("clicked", self.on_click)
self.pack_start(button, True, True, 0)
def on_click(self, widget):
msg = int(self.message)
while self.GUI.is_paused == False:
self.GUI.restart_window(str(msg))
msg += 1
while Gtk.events_pending():
Gtk.main_iteration()
sleep(1)
self.GUI.is_paused = True
class PauseButton(Gtk.Box):
def __init__(self, GUI):
Gtk.Box.__init__(self)
self.GUI = GUI
self.set_border_width(10)
button = Gtk.Button.new_with_label("Pause")
button.connect("clicked", self.on_click)
self.pack_start(button, True, True, 0)
def on_click(self, widget):
self.GUI.is_paused = True
class GUI:
def __init__(self):
self.is_paused = False
self.win = Gtk.Window()
self.window_grid = Gtk.Grid()
self.box = Gtk.Box(spacing=10)
self.label = Gtk.Label("Default label")
self.win.connect("delete-event", Gtk.main_quit)
self.start_window()
def start_window(self):
self.box.pack_start(LoopButton(self), True, True, 0)
self.box.pack_start(PauseButton(self), True, True, 0)
self.window_grid.add(self.box)
self.window_grid.add(self.label)
self.win.add(self.window_grid)
self.win.show_all()
def restart_window(self, label="Default label"):
self.window_grid.destroy()
self.window_grid = Gtk.Grid()
self.box = Gtk.Box(spacing=10)
self.label = Gtk.Label(label)
self.start_window()
def main():
app = GUI()
Gtk.main()
if __name__ == "__main__":
sys.exit(main())
Depending on what you really do in the loop there may be more necessary details, but below is an example of how looping is normally avoided in GLib/Gtk. The caveats of this method are: A) one iteration must be fast enough to not affect UI updates (a few milliseconds at most). B) The timing is not exact: the timeout function might not be called exactly 2 seconds after the previous call.
import gi
from gi.repository import GLib
class GUI:
def __init__(self):
# initialize the UI here...
# setup updates every two seconds
GLib.timeout_add_seconds(2, self.timeout_update)
def timeout_update(self):
# update your widgets here
print ("Updating UI now...")
# yes, we want to be called again
return True
I came across this rather unexpected problem. I have a gtk.TreeView with a single text column, that is rendered by gtk.CellRendererText. What I want is that the user can mark the displayed text using the mouse and get it into the clipboard by pressing ctrl+c. (I am referring to the very basic feature present in every webbrowser and texteditor). However, gtk won't let me do it. I have a simple example here, with non-markable / non-highlightable text:
import gtk
class TreeViewExample(gtk.TreeView):
def __init__(self):
gtk.TreeView.__init__(self)
self.get_selection().set_mode(gtk.SELECTION_NONE)
self.set_grid_lines(gtk.TREE_VIEW_GRID_LINES_HORIZONTAL)
# create model
self.list_store = gtk.ListStore(str)
self.list_store.append(['Hello, this is some \n multiline text.'])
self.list_store.append(['Another text.'])
self.set_model(self.list_store)
# create text column
col = gtk.TreeViewColumn('Text Column')
self.append_column(col)
cell = gtk.CellRendererText()
col.pack_start(cell, True)
col.add_attribute(cell, 'text', 0)
class MasterWindow(object):
def destroy(self, widget, data=None):
gtk.main_quit()
def __init__(self):
self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
self.window.set_size_request(500,500)
self.window.connect("destroy", self.destroy)
self.window.add(TreeViewExample())
self.window.show_all()
if __name__ == '__main__':
mw = MasterWindow()
gtk.main()
I could of course make the cell editable, because the editable mode provides the feature. But that is far from elegant, because it is some kind of popup, that breaks the line wrap and, well, edits the text. What i need is a cell, that is not selectable, editable or anything, but has text, that can be copied.
Does anyone have a solution? Thanks!
I made some changes in the code.
Try the code below, this example works well and I am sure that is the answer to your question.
Hope this helps you in the future of their knowledge and coding.
import gtk
class TreeViewExample():
def __init__(self):
self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
self.window.set_size_request(500,500)
model = gtk.ListStore(str)
model.append(['a'])
model.append(['b'])
model.append(['c'])
treeview = gtk.TreeView(model)
self.renderer = gtk.CellRendererText()
self.renderer.set_property('editable', True)
treeview.insert_column_with_attributes(-1, 'Copy-Pastable-Editable String', self.renderer, text=0)
self.window.add(treeview)
self.window.show_all()
if __name__ == '__main__':
TreeViewExample()
gtk.main()
I made some changes in the code. Trying to answer questions of #Flimm.I hpe Helps you #Flimm.
import gtk
class TreeViewExample():
def __init__(self):
self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
self.window.set_size_request(500,500)
self.model = gtk.ListStore(str,str)
self.model.append(['a','b'])
self.model.append(['c','a'])
self.model.append(['d','a'])
self.model.append(['e','a'])
self.treeview = gtk.TreeView(self.model)
self.renderer = gtk.CellRendererText()
self.renderer.set_property('editable', True)
self.renderer.connect('edited', self._text_changed, 0)
self.treeview.insert_column_with_attributes(-1, 'Copy-Pastable-Editable String', self.renderer, text=0)
self.treeview.insert_column_with_attributes(-1, 'Copy-Pastable-Editable String', self.renderer, text=1)
self.window.add(self.treeview)
self.window.show_all()
def _text_changed( self, w, row, new_value, column):
self.model[row][column] = new_value
if __name__ == '__main__':
TreeViewExample()
gtk.main()
nO ERROR AT run TIME.NO OTHER DEF WORKS OTHER THAN INIT
import wx
import os
from spectral import *
class Frame(wx.Frame):
def __init__(self, title):
wx.Frame.__init__(self, None, title=title, size=(1000,70),style=wx.MINIMIZE_BOX|wx.CLOSE_BOX|wx.RESIZE_BORDER|wx.SYSTEM_MENU|wx.CAPTION|wx.CLIP_CHILDREN)
self.Bind(wx.EVT_CLOSE, self.OnClose)
panel=wx.Panel(self,-1)
self.button=wx.Button(panel,label="Open",pos=(0,0),size=(50,30))
self.button1=wx.Button(panel,label="Save",pos=(51,0),size=(50,30))
self.button2=wx.Button(panel,label="ROI",pos=(102,0),size=(50,30))
self.button3=wx.Button(panel,label="Tone",pos=(153,0),size=(50,30))
self.slider=wx.Slider(panel,pos=(204,0))
self.button4=wx.Button(panel,label="Header",pos=(305,0),size=(50,30))
self.SetBackgroundColour((11, 11, 11))
self.Bind(wx.EVT_ENTER_WINDOW, self.onMouseOver)
self.Bind(wx.EVT_LEAVE_WINDOW, self.onMouseLeave)
self.Bind(wx.EVT_BUTTON, self.OnButtonClick,self.button)
self.filename=""
def OnButtonClick(self,event):
dlg=wx.FileDialog(self,message="Choose a file", defaultDir="",defaultFile="", wildcard="*.*", style=wx.OPEN)
if dlg.ShowModal==wx.ID_OK:
dlg.Destroy()
def onMouseOver(self, event):
self.SetBackgroundColor((179, 179, 179))
self.Refresh()
def onMouseLeave(self, event):
self.SetBackgroundColor((11, 11, 11))
self.Refresh()
def OnClose(self, event):
dlg = wx.MessageDialog(self,
"Do you really want to close BBvw ?",
"Confirm Exit", wx.OK|wx.CANCEL|wx.ICON_QUESTION)
result = dlg.ShowModal()
dlg.Destroy()
if result == wx.ID_OK:
self.Destroy()
app = wx.App(redirect=True)
top = Frame("BBvw")
top.Show()
app.MainLoop()
nO ERROR AT run TIME.NO OTHER DEF WORKS OTHER THAN INIT.I think I am missing something obvious.'int' not callable error when buttons are clicked.
The OnButtonClick() method is getting called, but you're not calling ShowModal correctly. You need to put the parentheses on it: ShowModal()
Then that will work. The OnClose() works for me. The Mouse ones don't, but I'm not sure why. You should ask about those on the wxPython mailing list.