gtk.MessageDialog with images and background image - python

I came across a function to insert image in a gtk dialog box. but there is some issue with it and not working.
messagedialog = gtk.MessageDialog(parent=None, flags=0, type=gtk.MESSAGE_INFO, buttons=gtk.BUTTONS_OK,\
message_format="Congratulations..!!")
messagedialog.set_image('scoreimg') #line 3
action_area = messagedialog.get_content_area()
lbl2=gtk.Label("Awesome")
action_area.pack_start(lbl2)
messagedialog.show_all()
messagedialog.run()
messagedialog.destroy()
The code is not working due to #line 3. Yes, the image is available to this code.
I guess, set_image is used to set background of a dialog box. I want to add some images in dialog box (not background this time).
Also, I am trying to eliminate the "bulb" from the dialog that appears based on type=gtk.MESSAGE_INFO though I need an "OK" button.
Any idea about how I can proceed with this?

here is Gtk3, which is basically the same.
messagedialog = Gtk.MessageDialog (None, Gtk.DialogFlags.MODAL, Gtk.MessageType.INFO,\
Gtk.ButtonsType.OK, "Congratulations..!!")
""" Assume you have it """
scoreimg = Gtk.Image ()
scoreimg.set_from_file ("yourpathhere") #or whatever its variant
messagedialog.set_image (scoreimg) #without the '', its a char
action_area = messagedialog.get_content_area()
lbl2=Gtk.Label("Awesome")
action_area.add(lbl2)
messagedialog.show_all()
messagedialog.run()
messagedialog.destroy()
A note: "set-image" property override the bulb icon (from gnome-hicolor)

Related

Python GTK3 How to bring widgets to the front?

I have an application (actually a plugin for another application) that presents a GTK notebook. Each tab contains a technical drawing of an operation, with a set of SpinButtons that allow you to alter the dimensions of the operation.
If you need more context, it's here: https://forum.linuxcnc.org/41-guis/26550-lathe-macros?start=150#82743
As can be seen above, this all worked fine in GTK2. The widgets (first iteration in a GTK_Fixed, then moved to a GTK_Table) were pre-positioned and the image (a particular layer of a single SVG) was plonked in behind.
Then we updated to GTK3 (and Python 3) and it stopped working. The SVG image now appears on top of the input widgets, and they can no-longer be seen or operated.
I am perfectly happy to change the top level container[1], if that will help. But the code that used to work (and now doesn't) is:
def on_expose(self,nb,data=None):
tab_num = nb.get_current_page()
tab = nb.get_nth_page(tab_num)
cr = tab.get_property('window').cairo_create()
cr.set_operator(cairo.OPERATOR_OVER)
alloc = tab.get_allocation()
x, y, w, h = (alloc.x, alloc.y, alloc.width, alloc.height)
sw = self.svg.get_dimensions().width
sh = self.svg.get_dimensions().height
cr.translate(0, y)
cr.scale(1.0 *w / sw, 1.0*h/sh)
#TODO: gtk3 drawing works, but svg is drawn over the UI elements
self.svg.render_cairo_sub(cr = cr, id = '#layer%i' % tab_num)
[1] In fact I will probably go back to GTK_Fixed and move the elements about in the handler when the window resizes, scaled according to the original position. The GTK_Table (deprecated) version takes over 2 minutes to open in the Glade editor.
Unless there is a more elegant way to do this too?

Drawing window border in Python xlib

I'm working on a window manager written using python's xlib bindings and I'm (initially) attempting to mimic dwm's behavior in a more pythonic way. I've gotten much of what I need, but I'm having trouble using X's built in window border functionality to indicate window focus.
Assuming I've got an instance of Xlib's window class and that I'm reading the documentation correctly, this should do what I want to do (at least for now) - set the window border of a preexisting window to a garish color and set the border width to 2px.
def set_active_border(self, window):
border_color = self.colormap.alloc_named_color(\
"#ff00ff").pixel
window.change_attributes(None,border_pixel=border_color,
border_width = 2 )
self.dpy.sync()
However, I get nothing from this - I can add print statements to prove that my program is indeed running the callback function that I associated with the event, but I get absolutely no color change on the border. Can anyone identify what exactly I'm missing here? I can pastebin a more complete example, if it will help. I'm not exactly sure it will though as this is the only bit that handles the border.
Looks like this was complete PEBKAC. I've found an answer. Basically, I was doing this:
def set_active_border(self, window):
border_color = self.colormap.alloc_named_color(
"#ff00ff"
).pixel
window.configure(border_width=2)
window.change_attributes(
None,
border_pixel=border_color,
border_width=2)
self.dpy.sync()
Apparently this was confusing X enough that it was doing nothing. The solution that I've stumbled upon was to remove the border_width portion from the window.change_attributes() call, like so:
def set_active_border(self, window):
border_color = self.colormap.alloc_named_color(
"#ff00ff"
).pixel
window.configure(border_width=2)
window.change_attributes(
None,
border_pixel=border_color
)
self.dpy.sync()
I hope this helps someone later on down the road!

Can I make a custom pygtk tooltip stay on when the cursor is over it?

Please look at the following snippet :
import gtk
def callback(widget, x, y, keyboard_mode, tooltip):
hbox = gtk.HBox(False, 8)
button = gtk.Button('Exit Tooltip')
label = gtk.Label('Tooltip text')
hbox.pack_start(label)
hbox.pack_start(button)
hbox.show_all()
tooltip.set_custom(hbox)
return True
label = gtk.Label('Test label')
label.set_has_tooltip(True)
label.connect('query-tooltip', callback)
Here I've created a custom tooltip with a close button in it. Now I want it to stay until i click that close button. Searching google was not that helpful. besides I would also like to know the signals/events that are emitted when a tooltip is being closed.
Similar problems are handled smoothly for JQuery/JavaScript/Ajax tooltips etc. but
for gtk/pygtk there is no luck :(
Thanks in advance ...
I had this issue as well, and as far as I know, there isn't any way to determine how long a tooltip stays up.
What I did (and recommend to you) is that you make your own "tooltip" and set it's background color to yellow, or whatever color you want, via an eventbox. Make sure you don't show it yet. This is just a simplified code, as you will need to position and size this in your project yourself.
color = gtk.gdk.rgb_get_colormap().alloc_color('black')
ebTooltip = gtk.EventBox()
btnTooltip = gtk.Button("Close")
ebTooltip.add(btnTooltip)
ebTooltip.modify_bg(gtk.STATE_NORMAL, color)
Now, you just need to hide and show this eventbox via your callbacks. To show it, call...
ebTooltip.show()
And, to hide it (probably on the "clicked" event of your close button)...
ebTooltip.hide()
Hope that solves your issue!

How to auto-scroll a gtk.scrolledwindow?

I have a treeview-widget inside a ScrolledWindow, which is populated during runtime. I want the ScrolledWindow to auto-scroll to the end of the list. I "solved" the problem, by adjusting the vadjustment of the ScrolledWindow, everytime a row is inserted into the treeview. e.g:
if new_line_in_row:
adj = self.scrolled_window.get_vadjustment()
adj.set_value( adj.upper - adj.page_size )
If i run the code in an interactive ipython session and set the value by myself, everything works as expected.
If i run the code with the default python interpreter, the auto-scroll doesn't work all the time. I debugged the code and the problem seems be, that the adjustment values have some kind of "lag" and are only changed after some period of time.
My question is: how do I scroll, reliably, to maximum position of the ScrolledWindow? is a special signal generated which i can use? or is there a better way to set the adjustment-value?
After widening my search-radius, i found a ruby-related answer. since the problem is gtk-related, it should be able to be solved in any language like this:
you connect the widget which changes, in my case the treeview, with gtk.widget's 'size-allocate' signal and set the gtk.scrolledwindow value to "upper - page_size". example:
self.treeview.connect('size-allocate', self.treeview_changed)
...
def treeview_changed(self, widget, event, data=None):
adj = self.scrolled_window.get_vadjustment()
adj.set_value( adj.upper - adj.page_size )
link to the original post at ruby-forum.com:
hint hint
fookatchu's answer can be improved so that the callback could be used by multiple widgets:
def treeview_changed( self, widget, event, data=None ):
adj = widget.get_vadjustment()
adj.set_value( adj.upper - adj.pagesize )
Python Gtk 3 version:
adj.set_value(adj.get_upper() - adj.get_page_size())
The accepted answer has helped me figure out a Rust solution in gtk-rs to the auto-scroll to end of content issue.
Here's a Rust snippet that might help others:
// Imports used for reference
use gtk::{TextBuffer, TextView, TextBufferBuilder, ScrolledWindow, ScrolledWindowBuilder};
// The text buffer where the text is appended later
let text_buffer: TextBuffer = TextBufferBuilder::new().build();
// The containing text view that holds the text buffer
let text_view: TextView = TextView::new_with_buffer(&text_buffer);
// The scrolled window container with fixed height/width that holds the text view
let scrolled_window: ScrolledWindow = ScrolledWindowBuilder::new()
.min_content_height(400)
.min_content_width(600)
.child(&text_view)
.build();
// Have the text view connect to signal "size-allocate"
text_view.connect_size_allocate(clone!(#weak scrolled_window => move |_,_| {
let adj = scrolled_window.get_vadjustment().unwrap();
adj.set_value(adj.get_upper() - adj.get_page_size());
}));
// ...
// Later on, fill buffer with some text.
text_buffer.insert(&mut text_buffer.get_end_iter(), "This is my text I'm adding");
None of the suggested solutions worked for me, but I was able to get the desired behavior doing this (using GTk4 bindings for Go):
adj := scrolledWindow.VAdjustment()
adj.SetUpper(adj.Upper() + adj.PageSize())
adj.SetValue(adj.Upper())
The other solutions would move the scrolled window (mine contained a list box) down to the 2nd-to-last item, but not show the last item. The way it was acting made me think that the upper limit needed to be increased, so I tried increasing it by page-size then setting the scroll value to the new upper limit.
Still need the callback (I used a textView rather than treeView):
textView = Gtk.TextView()
scrolledWindow = Gtk.ScrolledWindow()
def textViewChanged( self, widget ):
adjustment = scrolledWindow.get_vadjustment()
adjustment.set_value( adjustment.get_upper() - adjustment.get_page_size() )
textView.connect( "size-allocate", textViewChanged )

pygtk: how to force message dialogs to show up in the center of the screen?

I have a glade GUI and i'm using dome gtk.MessageDialog widgets created with pygtk for user interaction. My problem is that whenever I throw a dialog message on the screen, they show up all over the place. One might show up on the top right corner, the next on the bottom left, top left, mid left etc...
Is there a way to force these things to show up in the center of the screen or at the position where the parent window is at?
Never mind. Found the solution.
For others who might wander about the same thing, the solution to this problem lies in specifying a parent value to the gtk.MessageDialog construct.
If you are using a glade gui, in your class, and your glade xml is loaded in to a variable named 'gui', it would look like this:
#!/usr/bin/env/python
par = self.gui.get_widget('your_parent_window')
msg = gtk.MessageDialog(type=gtk.MESSAGE_INFO, buttons = gtk.BUTTONS_OK, parent=par)
if msg.run():
msg.destroy()
return None
Check out the reference material at PyGTK 2.0 Reference Manual
I have not had a chance to try this but MessageDialog seems to be derived from Window which has a set_position method.
This method accepts one of the following:
# No influence is made on placement.
gtk.WIN_POS_NONE
# Windows should be placed in the center of the screen.
gtk.WIN_POS_CENTER
# Windows should be placed at the current mouse position.
gtk.WIN_POS_MOUSE
# Keep window centered as it changes size, etc.
gtk.WIN_POS_CENTER_ALWAYS
# Center the window on its transient parent
# (see the gtk.Window.set_transient_for()) method.
gtk.WIN_POS_CENTER_ON_PARENT
None of the provided solutions will work if your parent window is not yet shown, that is if the messagedialog is to be shown during the instantiation of a class (your class, not the "parent" window class). During this time Gtk has not yet placed the window, even if code for messagedialog is after the code that shows the window. Which means your dialog box will be somehow "parentless" and the message dialog will appear wherever it likes...
My naive solution for that problem...
GObject.timeout_add(interval=50, function=self.stupid_dialog_1)
and
def stupid_dialog_1(self):
par = self.gui.get_widget('your_parent_window')
msg = gtk.MessageDialog(type=gtk.MESSAGE_INFO, buttons = gtk.BUTTONS_OK, parent=par)
# do anything here...
return False #stop the timer...

Categories