ipywidget interactive hiding visibility - python

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)

Related

PyQt make QFrame appear on top of another widget

So my application's main part consists of a QFrame which contains 2 other QFrames (left one for a menu, right for the content of the current page selected) I made the layout in QtDesigner as follows:
I added an animation for opening/closing the menu on the left, making the QPushButton texts visible when open, hiding them when closed (Only the icon shows in that case) by increasing the QFrame's width.
def ToggleMenu(self):
width = self.ui.frame_left_menu.width()
defaultWidth = 70
toggleWidth = 200
if width == defaultWidth:
toggleWidth = 200
self.ui.frame_content_right.lower()
self.ui.frame_left_menu.raise_()
else:
toggleWidth = 70
self.ui.frame_left_menu.lower()
self.ui.frame_content_right.raise_()
self.animation = QtCore.QPropertyAnimation(self.ui.frame_left_menu, b"minimumWidth")
self.animation.setDuration(300)
self.animation.setStartValue(width)
self.animation.setEndValue(toggleWidth)
self.animation.setEasingCurve(QtCore.QEasingCurve.InOutQuart)
self.animation.start()
ToggleMenu() is called when the user clicks on the menu button (thats outside of frame_center, increasing/decreasing its width.
When opening the menu, its width is increased, thus pushing the right QFrame along, making the available space smaller for actual content.
I would like to be able to make it so the menu is displayed above the content QFrame when opened. I tried calling raise_() and lower() on open/close, but that doesn't seem to change anything, I think that is because they are not overlapping to begin with, given the layout above.
I would like to avoid creating the layout at runtime if possible. How could I solve this?

Return removed title bar of a QDockWidget for drag-ability

So we can remove a title bar of a QDockWidget like this:
self.dW1.setTitleBarWidget(QtGui.QWidget(self.dW1))
Now the dock widgets are not undockable and drag-able. So Is there a way to put the title bar back?
Or perhaps another (even better) way, is there a way to delegate the drag-ability (of the hidden title bar) to the whole window (which I would expect from the code fraction above, but it doesn't work that wqay) or the tab leaf?
Just to avoid some dead ends: I've tested some solutions involving dragging QTabWidget tabs, but they lacked the flexibility of tabbed QDockWidgets (like undocking it to new window and docking to different positions of the windows).
If you want the default title bar to be returned, then you must pass None:
self.dW1.setTitleBarWidget(None)

highlight clicked items in tkinter canvas?

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. :)

Don't set a Gtk.TreeView's selection when focusing?

The following code displays a window with a button and tree view. A handle for the 'clicked' signal is attached to the button and focuses the tree view. When the window is initially displayed, the tree selection has no selected items, but when the tree view receives focus, the first item is automatically selected. Is there a way to keep a selection from being made when the tree view receives focus?
Before click, button has focus and tree selection has no selected items. After click, tree view has focus, but an item has been selected.
The issue that arises from this is that I have an interface that keeps some things in sync by attaching to the 'changed' signal on the tree selection of the tree view. When the window is displayed, depending on where the tree views are in the interface, they may receive focus by default. That causes a 'changed' signal, and unexpected synchronization happens. It's possible to call set_can_focus(False) for all the tree views, but that:
only prevents keyboard cycling focus, not programmatic focus, and the selection still turns on with programmatic focus; and
seems to disable the ability to deselect a selection (e.g., by control-clicking on a row).
Similarly I can use grab_default to ensure that something else gets focus first when the window is displayed, but it doesn't keep a stray focus event from making an unexpected selection.
Based on a posted answer that says that says that selection mode SINGLE "requires at least one item to be selected", and that that explains why an element is selected on focus, I looked more into the selection mode constants. Of these, SINGLE and BROWSE seem most relevant. The pygtk documentation, GTK Selection Mode Constants, only says that:
gtk.SELECTION_SINGLE A single selection allowed by clicking.
gtk.SELECTION_BROWSE A single selection allowed by browsing with the pointer.
The GTK+3 documentation, enum GtkSelectionMode, goes into a bit more detail:
GTK_SELECTION_SINGLE Zero or one element may be selected.
GTK_SELECTION_BROWSE Exactly one element is selected. In some
circumstances, such as initially or during a search operation, it’s
possible for no element to be selected with GTK_SELECTION_BROWSE. What
is really enforced is that the user can’t deselect a currently
selected element except by selecting another element.
I don't see anything here to suggest that at least one element must be selected when the selection mode is SINGLE.
Here's code to reproduce the window and serve as an example.
from gi.repository import Gtk
# A ListStore with some words
list_store = Gtk.ListStore(str)
for selection in "Can a machine think?".split():
list_store.append([selection])
# A TreeView with a single column
tree_view = Gtk.TreeView(model=list_store)
cell_renderer = Gtk.CellRendererText()
tree_view_column = Gtk.TreeViewColumn(cell_renderer=cell_renderer,text=0,title='Words')
tree_view.append_column(tree_view_column)
# A button to focus the list
focus = Gtk.Button(label='Focus List')
focus.connect('clicked',lambda *_: tree_view.grab_focus())
# A Box to hold everything, and a Window for the Box.
box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
box.add(focus) # button on top gets initial focus
box.add(tree_view) # tree_view below doesn't, and has no selected items
window = Gtk.Window()
window.add(box)
window.show_all()
Gtk.main()
Looking at the source in root/gtk/gtktreeview.c for tree_view.grab_focus(), we can see that gtk_tree_view_focus_to_cursor always gets called, and selects the first element. You can work around this, in some cases, though.
This is a nasty hack.
It overrides the grab_focus method, stores the selection before calling grab_focus, and clears the selection afterwards if there was no selection before.
def tree_view_grab_focus():
selection = tree_view.get_selection()
_, selected = selection.get_selected()
Gtk.TreeView.grab_focus(tree_view)
if selected is None:
selection.unselect_all()
tree_view.grab_focus = tree_view_grab_focus
Unfortunately it only applies when calling grab_focus from Python, other callers (such as GTK's keyboard navigation) don't.

python tkinter: Custom menu while pulling down

I'm learning creating software with Python and Tkinter. Now I need to change menu items for different conditions, but could not find an easy way to do it. Well, let me try to explain my question clearly using an example:
Like shown in the figure, I have a listbox on the left and a listbox on the right. I also have a menu to move the items around, the commands are "move to right", "move to left" and "exchange". The following conditions are considered:
When I only get items selected in left listbox, I want only the command "move to right" enabled, like shown in the figure.
When I only get items selected in right listbox, I want only the command "move to left" enabled.
When I get items selected in both listboxes, I want all commands enabled.
When I get no item selected, I want all commands disabled.
I know I can get the work done by binding events "ListboxSelect" and "Button-1" to some functions, and then use the functions to configure the menu. But it is really a complex work when I have five listboxes in the actual software. So I am wondering whether there is an easy way to do this, like overloading some functions in tkinter.Menu class (I tried overloading post(), grid(), pack() and place(), none of them works).
Any idea is welcomed.
I think what you want to use is the postcommand to modify the menu as appropriate. If you're going to have multiple listboxes, the simplest solution may be to implement your own class. Here's a rough idea:
class EditMenu(Tkinter.Menu):
def __init__(self, parent, listboxes, **kw):
self.commandhook = kw.get('postcommand', None)
kw['postcommand'] = self.postcommand
super(EditMenu, self).__init__(parent, **kw)
self.listboxes = listboxes
self.add_command(label="Move to right", command=self.move_to_right)
self.add_command(label="Move to left", command=self.move_to_left)
self.add_command(label="Exchange", command=self.exchange)
def postcommand(self):
for i in xrange(3):
# do some checks for each entry
# and set state to either Tkinter.DISABLED or Tkinter.NORMAL
self.entryconfig(i, state=state)
if self.commandhook is not None:
self.commandhook()
# Implement your three functions here
If you start to add more items, probably what you'll want to do is create a class for each menu item. In that class you could put in the logic for enable/disable and the callback function implementation. Comment if you'd like to see an example.

Categories

Resources