General idea:
Many items (majority small images) are created on the canvas. The user can click on any item and move it.
I need the user to know which item was last clicked, by showing (drawing) a border/change brightness/any method.. around that item.
Is there any Image/item options to help apply this idea.
You can achieve that by writing a simple modify appearance method for a widget last clicked. Here is the sample code. Below we are performing two actions. First changing the appearance of last widget to normal and then changing the appearance of last clicked widget to highlight it.
def modifyAppearance(self, widget):
global previously_clicked
if 'previously_clicked' in globals():
# rolling back the appearance of previous widget to normal
previously_clicked['bg'] = widget['bg']
previously_clicked['activebackground'] = widget['activebackground']
previously_clicked['relief'] = widget['relief']
# changing the appearance of the last clicked widget
widget['bg'] = 'green'
widget['activebackground'] = '#33B5E5'
widget['relief'] = 'sunken'
previously_clicked = widget
You will need to define global previously_clicked in other methods also, where you will be defining the widgets. You can refer my full code here. It has this functionality
For example this is your button-
B1 = Button(root, text = "Click me", command = clickme)
we can pass more parameters here such as--
highlightcolor=
The color to use for the highlight border when the button has focus. The default is system speciific. (highlightColor/HighlightColor)
and
highlightthickness=
The width of the highlight border. The default is system specific (usually one or two pixels). (highlightThickness/HighlightThickness)
...
OR
...
Whenever the button is clicked you must be specifying some action to do in a function. What you can do is you can tell that function to slight increase the thickness of border by above parameters. :)
Related
I would like to make an interactive module with ipywidgets.
So far so good but I'm stuck.
I want to hide the visibility of a certain ipywidget object dependent on a certain situation, and I want my printed text to show up above the widget and stay there.
dropdown=widgets.Dropdown(
options={'Coffee machine': 1, 'Washing machine': 2, 'Water Heater': 3, 'Heating System': 4, 'Dryer': 5, 'Oven': 6, 'Microwave': 7, 'Other':8},
value=1,
description='Apparaat:',
)
text_new=widgets.Text()
def text_field(value):
if(value==8):
display(text_new)
text_new.on_submit(handle_submit)
else:
text_new.visible(False) #Doesn't work but I want something like this
print("Today you had an increase in electricity consumption, would you like to name this device?") #This just be above the dropdown menu and be stuck
i=widgets.interactive(text_field, value=dropdown)
display(i)
What this does now:
When "Other" is checked in the dropdown menu, a text box appears where the user can type something.
However, when checking another machine, the text box stays there.
I just need a "hide" function but I can't seem to find one that works.
Also, after checking another option on the dropdown, the print dissapears, not coming back.
Had same problem so i found in
boton.layout.visibility = 'hidden'
or
check.layout.display = 'none'
they made some changes... i got if from here
Cannot create a widget whose initial state is visible=False
Given a widget:
import ipywidgets
button = ipywidgets.Button()
There are two direct ways to hide the the widget, with a notable difference.
Hide and unhide the widget without affecting overall page layout:
# Turn the widget "invisible" without affecting layout
button.layout.visibility = "hidden"
# Make the widget visible again, layout unaffected
button.layout.visibility = "visible"
Hide and unhide the widget and collapse the space that the widget took up:
# Hide widget and collapse empty space
button.layout.display = "none"
# Re-add the widget, adjusting page layout as necessary.
button.layout.display = "block"
When to use each one? As a rule of thumb, use layout.visibility so the page layout is not constantly jumping around as visibility is toggled. However, for very large widgets, consider using layout.display to avoid huge blank spaces.
For more general CSS information that applies here, see What is the difference between visibility:hidden and display:none?
In addition to the accepted answer, if you want to dynamically change the visibility of a control, you can declare the layout variable and reuse.
layout_hidden = widgets.Layout(visibility = 'hidden')
layout_visible = widgets.Layout(visibility = 'visible')
Like attach to an event:
def visible_txt(b):
text_box.layout = layout_visible
def hidden_txt(b):
text_box.layout = layout_hidden
btn_visible.on_click(visible_txt)
btn_hidden.on_click(hidden_txt)
I'm building a GUI that have 2 text widgets. (I mean it has a bunch of things in it but the sake of this question lets leave it at 2 text widgets). What I want to do is that when I scroll the one text widget with the arrow key the other text widget also scrolls at the same time. I was able to accomplish this with the scrollbar (not shown in code) but, not with the arrow keys. I want the arrow key normal behaviour on both text areas at the same time. That is to say that when it gets to the bottom of the viewable text it scrolls down but if I scroll back up the text doesn't move just the arrow. You know, like any normal text editor. So the question is how do I accomplish this? Here is a snippet of my code.
#create Text widgets
descriptionTextField = Text(mainframe, width=40, height=10)
descriptionTextField.grid(column=2, row=5, sticky=(W))
descriptionTextField.bind("<Down>", OnEntryDown)
descriptionTextField.bind("<Up>", OnEntryUp)
pnTextField = Text(mainframe, width=40, height=10)
pnTextField.grid(column=3, row=5, sticky=(W))
pnTextField.bind("<Down>", OnEntryDown)
pnTextField.bind("<Up>", OnEntryUp)
#here are what I have for code that **DOESN'T** do what I want.
def OnEntryDown(event):
descriptionTextField.yview_scroll(1,"units")
pnTextField.yview_scroll(1,"units")
def OnEntryUp(event):
descriptionTextField.yview_scroll(-1,"units")
pnTextField.yview_scroll(-1,"units")
There has to be a way to find out when the next arrow key will be greater than the viewable area (in this case 10) and then scroll other wise just move the cursor.
NOTE: I can't get the code for up "< Up >" and down "< Down >" arrow to show up in my code above but believe me it is there.
Instead of trying to duplicate what the arrow key does, a different method would be to sync the two windows after the key has been processed (ie: set the yview of one to the yview of the other)? You can move the insertion cursor at the same time if you want. This technique will only work if the two widgets have the same number of lines.
While the right way would be to adjust the bindtags so that you create a binding after the class bindings, you can avoid that complication with the knowledge that tkinter processes the key press events. This means you can add bindings to key release events. It yields a tiny lag though.
It would look something like this:
descriptionTextField("<KeyRelease-Up>", OnArrow)
descriptionTextField("<KeyRelease-Down>", OnArrow)
pnTextField("<KeyRelease-Up>", OnArrow)
pnTextField("<KeyRelease-Down>", OnArrow)
...
def OnArrow(event):
widget = event.widget
other = pnTextField if widget == descriptionTextField else descriptionTextField
other.yview_moveto(widget.yview()[0])
other.mark_set("insert", widget.index("insert"))
Using bindtags eliminates the lag. You can set it up like this:
for widget in (descriptionTextField, pnTextField):
bindtags = list(widget.bindtags())
bindtags.insert(2, "custom")
widget.bindtags(tuple(bindtags))
widget.bind_class("custom", "<Up>", OnArrow)
widget.bind_class("custom", "<Down>", OnArrow)
I want to make the text under the selection, in variable 'a' to appear as a label of the menu.
Here is the code:
def popup(event):
a=t_start.get("sel.first", "sel.last")
menu.post(event.x_root, event.y_root)
return a
def insert_word():
pass
t_start.bind("<Button-3>", popup)
menu = Menu(root, tearoff=0)
menu.add_command(label="Set selection 1", command=set_selection_1)
menu.add_command(label="Set selection 2", command=set_selection_2)
menu.add_command(label="%s" %popup, command=set_selection_2)
Right now, all I get is function popup address.
If I try popup.a, I get an error, function has no attribute 'a'. How do I overcome this and get whatever is in 'a' to be printed as menu label?
Callback methods like popup are not supposed to return anything. Instead, you should manipulate the menu from inside the function.
Also, as suggested by Brian, you probably rather want to modify an existing entry in the menu, instead of adding a new one each time you click the button. In this case, create the entry outside the function (like you do now), but use some placeholder for the label.
def popup(event):
a = t_start.get("sel.first", "sel.last")
menu.post(event.x_root, event.y_root)
menu.add_command(label=a, command=set_selection_2) # add to menu
# menu.entryconfig(2, label=a) # modify existing entry
If you want to change the text on a menu, you must use the entryconfig method. For example, to change the text of the first item you would do:
menu.entryconfig(0, label=a)
I want to change the label of the 'Apply' button of a gtk.Assistant to 'Start'. I can't find the corresponding gtk.Button widget in the Assistant instance.
Here's some basic code for a two-page Assistant:
import gtk
a = gtk.Assistant()
page = gtk.CheckButton("Something optional")
a.append_page(page)
a.set_page_type(page, gtk.ASSISTANT_PAGE_CONTENT)
a.set_page_title(page, "Make decisions")
a.set_page_complete(page, True)
page = gtk.Label("Alright, let's build some foo.")
a.append_page(page)
a.set_page_type(page, gtk.ASSISTANT_PAGE_CONFIRM)
a.set_page_title(page, "Confirm")
a.set_page_complete(page, True)
a.connect('delete-event', gtk.main_quit)
a.connect('close', gtk.main_quit)
a.show_all()
gtk.main()
On the final page you'll see the 'Apply' button. I want to change that text to 'Start'.
gtk.Assistant.children() and .get_children() return the list of page widgets.
gtk.Assistant.get_child() returns None.
gtk.Assistant.get_action_area() isn't a method.
Here's a link to the documentation.: http://www.pygtk.org/docs/pygtk/class-gtkassistant.html
How do I find the gtk.Button I'm interested in?
I managed to find a solution while experimenting with workarounds.
gtk.Assistant overrides the gtk.Container.get_children() method with something that returns the list of pages, but it is still in fact the parent of a gtk.HBox() which contains the buttons for 'Next', 'Apply', 'Cancel', etc.
The method gtk.Assistant.add_action_widget() adds a widget to the so-called "action area". It turns out this is the HBox containing the relevant buttons. The following function will produce a reference to the HBox:
def get_buttons_hbox(assistant):
# temporarily add a widget to the action area and get its parent
label = gtk.Label('')
assistant.add_action_widget(label)
hbox = label.get_parent()
hbox.remove(label)
return hbox
Then the buttons are retrieved using get_buttons_hbox(a).get_children().
for child in get_buttons_hbox(a).get_children():
print child.get_label()
This prints:
gtk-goto-last
gtk-go-back
gtk-go-forward
gtk-apply
gtk-cancel
gtk-close
So the following code solves the problem (using get_buttons_hbox() defined above):
for child in get_buttons_hbox(a).get_children():
label = child.get_label()
if label == 'gtk-apply':
child.set_label('Start')
I'm not sure this will be possible with pygtk. If you switch to GObject Introspection with python you can set a fully custom action area. From the Gtk3 GtkAssistant documentation:
If you have a case that doesn't quite fit in GtkAssistants way of
handling buttons, you can use the GTK_ASSISTANT_PAGE_CUSTOM page type
and handle buttons yourself.
and
GTK_ASSISTANT_PAGE_CUSTOM Used for when other page types are not
appropriate. No buttons will be shown, and the application must add
its own buttons through gtk_assistant_add_action_widget().
I'm attempting to write a basic Tkinter GUI that has a Text widget at the top, then a Button widget left aligned under it, then another Text widget underneath the button. The problem I'm having is, after packing the Button widget to the left, when I then go to pack the second Text widget, it puts it next to the button on the right, rather than underneath the button. This happens regardless of what I set the side argument to for the second Text widget Here's a simple piece of code that demonstrates this behaviour:
from Tkinter import *
root = Tk()
w = Text(root)
w.pack()
x = Button(root, text="Hi there!")
x.pack(side=LEFT)
y = Text(root)
y.pack(side=BOTTOM)
root.mainloop()
So how would I go about setting up the second Text widget so that it appears below the button, rather than to the right of it?
There are generally two solutions to layout problems:
switch to using grid. It becomes real easy to do layouts like what you are trying to accomplish. Grid can solve probably 95% of all layout issues (it's amazing when you think about it -- Tk does with one manager what most toolkits need half a dozen to accomplish!)
use multiple frames. If some widgets need to be stacked top-to-bottom and some left-to-right you can't always get what you want packing everything in a single frame. Use one frame for the top-to-bottom parts of the layout and additional frames for the left-to-right content.
Also realize that widgets don't have to be children of the widget in which they are packed/gridded. You can use the "in" parameter to put widgets in some other container than their parent.
For example, in your specific example you can create three frames, top, middle, bottom. Pack these top-to-bottom in your toplevel window. Then you can pack the first text widget in the top, the button or buttons horizontally in the middle, and the other text widget in the bottom.
The advantage to such an approach is that it makes it much easier to change the layout in the future (which in my experience always happens at some point). You don't have to re-parent any of your widgets, just pack/place/grid them in some other container.
In your short example it doesn't make much difference, but for complex apps this strategy can be a life saver.
My best advice is this: layout isn't an afterthought. Do a little planning, maybe even spend five minutes drawing on some graph paper. First decide on the major regions of your app and use a frame or some other container for each (paned window, notebook, etc). Once you have those, do the same divide-and-conquer approach for each section. This lets you use different types of layout for different sections of your app. Toolbars get horizontal layout, forms might get vertical layout, etc.
I was initially misunderstanding how packing worked and didn't realise that the entire left side was being "claimed" when i did x.pack(side=LEFT). What I found after reading this and the answer by Alex here is that I was not really after having x packed to the left side at all, but rather having it anchored to the left, using anchor=W (W for West) instead of side=LEFT. My revised code snippet which does what I was after looks like this:
from tkinter import *
root = Tk()
w = Text(root)
w.pack()
x = Button(root, text="Hi there!")
x.pack(anchor=W)
y = Text(root)
y.pack(side=BOTTOM)
root.mainloop()
This way x is not "claiming" the left side anymore, it's just aligned to the left (or West) within its block of space.
Packing happens in the order the .pack methods are called, so once x has "claimed" the left side, that's it -- it will take up the left portion of its parent and everything else within its parent will be to its right. You need a Frame to "mediate", e.g....:
from Tkinter import *
root = Tk()
w = Button(root, text="Mysterious W")
w.pack()
f = Frame(root)
x = Button(f, text="Hi there!")
x.pack()
y = Button(f, text="I be Y")
y.pack(side=BOTTOM)
f.pack(side=LEFT)
root.mainloop()
(changed Texts to Buttons for more immediate visibility of layout only -- the Tkinter on this Mac doesn't show Texts clearly until they have focus, but Buttons are quite clear;-).
Do it the same way that WebView does using the Mosaic Canvas Widget Sets internals(which are very similar to Tk). The trick is that the second identical named Frame Object works as a Block Level Float(inline:block;) for everything placed after it and everything that calls "fr" already will automatically begin over inside of it.
You can have many doing this of TOP aligned widgets and simply add another identical named Frame where you want to break between side=LEFT's. Works after Bottom also.
fr=Frame(root)
fr.pack(fill=X, side=TOP)
block1=Label(fr)
block1.pack(side=LEFT)
block2=Label(fr)
block2.pack(side=LEFT)
block3=Button(fr)
block3.pack(side=LEFT)
# NAME IT THE SAME ID NAME AS THE FIRST MAIN FRAME...
fr=Frame(root)
fr.pack(fill=X, side=TOP)
# These NOW jump into the second Frame breaking the side=LEFT in new Frame
block4=Label(fr)
block4.pack(side=LEFT)
block5=Label(fr)
block5.pack(side=LEFT)
# AND THEY CONTINUE GOING side=LEFT AFTERWARDS.