Dash Button n-clicks not triggering callback - button

I've tried both dcc.Button and dbc.Button. Same issue. When I click the button, it shows that it is clicked (highlighted, border), but is not triggering the callback. It stays in the clicked state indefinitely. I've tested my backend code separate from dash and it works fine.
I'm trying to dynamically add a div to the side-bar content, but my other callback has the same issue.
#app.callback(
Output('side-bar', 'children'),
Input("login-button", "n-clicks"),
[State("username", "value"),
State("password", "value"),
State("side-bar", "children")])
def get_project_reports(clicks, un, pw, children):
if clicks is None or un is None or pw is None:
raise PreventUpdate
else:
....DO STUFF....
option_list = df_proj_list["Project Title"].to_list()
select_project = html.Div([
dbc.Label("Select Project"),
html.Hr(),
dbc.Select(
option_list,
id={
'type': 'filter-dropdown',
'index': clicks
})
])
children.append(select_project)
return children

Related

Clicking links with the middle mouse button in Python3/Qt6

I used a Python3 script under GTK, where I clicked on a link with the left mouse button to open it in the same window and on a middle mouse button to open it in a separate window.
I am now in the process of migrating this script from GTK to Qt6.
The problem is that I cannot intercept the middle mouse button in conjunction with a clicked link:
My browser window is based on QWebEngineView, I can intercept mouse button clicks with an event filter (eventFilter()), and I can intercept clicked links within the acceptNavigationRequest() function of a QWebEnginePage.
The URL of the clicked link is only available in acceptNavigationRequest(), but this function is only called by Qt6 when I use the left mouse button, not, as desired, the middle mouse button (neither does control + left mouse button work).
How can I let a middle mouse button click be recognized in a navigation request?
Debian 11.6 Bullseye, Python 3.9.2, PyQt6-Qt6 6.4.1
With the help of #musicamante (note the comments in the original post), I solved my problem this way:
g_mouse_button = '--'
class MyWebEngineView(QWebEngineView):
def __init__(self):
...
class MyEventFilter(QObject):
def eventFilter(self, obj, event):
global g_mouse_button
...
if event.button() == Qt.MouseButton.MiddleButton:
g_mouse_button = 'middle'
...
...
class MyWebEnginePage(QWebEnginePage):
def acceptNavigationRequest(self, url, ttype, isMainFrame):
global g_mouse_button
if ttype == QWebEnginePage.NavigationType.NavigationTypeLinkClicked and \
g_mouse_button == 'middle':
<open link in new window>
g_mouse_button = '--'
return False # ignore
return True # process
def createWindow(self, window_type):
return self
if __name__ == "__main__":
...
event_filter = MyEventFilter()
g_app.installEventFilter(event_filter)
...

Changing cursor on a bokeh map

I've made a map using Bokeh, like the first example on this page, except the user can zoom in/out by scrolling up/down, and can tap circles I've added to the map to select them.
At the moment when the cursor is over the map it's the default arrow. If I click and drag the map the cursor changes to the text cursor for some reason. It doesn't change with any other action.
I'd like to be able to change the cursor appearance so that:
When over the map it's the grab cursor
When dragging the map it's the grabbing cursor
When over a circle it's the pointer cursor
I can achieve (1) with:
.bk { cursor: grab; }
but I'm not sure how to achieve the other two.
Following suggestions from the other post I came with this: (works for Bokeh v1.3.0):
from bokeh.models import CustomJS, HoverTool
from bokeh.plotting import figure, show
p = figure(tools='pan, tap, reset')
p.circle(x=[1,2,3], y=[1,2,3], size=30)
code_pan_start = '''
Bokeh.grabbing = true
var elm = document.getElementsByClassName('bk-canvas-events')[0]
elm.style.cursor = 'grabbing'
'''
code_pan_end = '''
if(Bokeh.grabbing) {
Bokeh.grabbing = false
var elm = document.getElementsByClassName('bk-canvas-events')[0]
elm.style.cursor = 'grab'
}
'''
code_hover = '''
if((Bokeh.grabbing == 'undefined') || !Bokeh.grabbing) {
var elm = document.getElementsByClassName('bk-canvas-events')[0]
if (cb_data.index.indices.length > 0)
elm.style.cursor = 'pointer'
else
elm.style.cursor = 'grab'
}
'''
p.js_on_event('panstart', CustomJS(code = code_pan_start))
p.js_on_event('panend', CustomJS(code = code_pan_end))
p.add_tools(HoverTool(callback = CustomJS(code = code_hover)))
show(p)
You could potentially use the PanStart and PanEnd events to set/reset the cursor on drag operations. I think the hover will be difficult to achieve. Currently there is a callback property on hover tools that can be used trigger JS code when an inspection happens on a point. But it only fires when there is an inspection, there is no corresponding event or hook for "un-inspection" so I am not sure how you would reliably clear the cursor state when the user is no longer hovering over the circle.

How to receive dropEvent when not a top level widget?

Edit: this issue seems to be specific to Qt version 5.12.0. See the answers for more details and for a workaround
I'm trying to implement a drop zone for loading files into my application.
It works when I just show the widget as a top level widget, but it stops working as soon as I include it into another parent widget.
The problem is, altough I'm receiving dragEnterEvent and accepting it, I never see the dropEvent.
This is my widget:
class FileDropZone(qt.QLabel):
"""Target area for a drag and drop operation"""
height = 33
def __init__(self, text="Add file", parent=None):
super().__init__(text, parent)
stylesheet = """
QLabel {
border: 2px dotted #B4BDBA;
qproperty-alignment: AlignCenter;
}
"""
self.setStyleSheet(stylesheet)
self.setAcceptDrops(True)
self.setFixedHeight(self.height)
def dragEnterEvent(self, event):
print("in drag enter event")
if event.mimeData().hasUrls():
print("hasUrls()")
event.acceptProposedAction()
def dropEvent(self, event):
print("in drop event")
urls = event.mimeData().urls()
for url in urls:
print(url.isLocalFile(), url.toLocalFile())
This is how I manage to make it work:
app = qt.QApplication([])
a = FileDropZone()
a.show()
app.exec_()
And this is the example where it does not work (dragEnter works, both prints are properly printed, but dropEvent does not print anything):
app = qt.QApplication([])
a0 = qt.QWidget()
l = qt.QHBoxLayout(a0)
a1 = FileDropZone("drop here", a0)
l.addWidget(a1)
a0.show()
app.exec_()
Any clues about what is broken? Does the parent need to forward the event, and if so, how should I implement it?
It looks like it is a bug which was introduced in Qt 5.12.0 and will be fixed in Qt 5.12.1, see this discussion and this bug report.
In the meantime:
The problem can be worked around by reimplementing dragMoveEvent() and accepting the event there too.
i.e. add e.g. the following method to the FileDropZone class:
def dragMoveEvent(self, event):
print("in drag move event")
if event.mimeData().hasUrls():
print("hasUrls()")
event.acceptProposedAction()

How to prevent awesome from changing focus when a mouse click occurs?

I'm using AwesomeWM 4.2 under Xfce4.
I'm using xfpanel. In rc.lua, I have done the following to prevent the xfpanel getting focus:
-- from https://github.com/zhangkun83/awesome-config/blob/d947e70041fad3e5f34bb832162cacaac62736b1/rc.lua#L492)
{ rule = { type = "dock" },
properties = {
border_width = 0,
titlebars_enabled = false,
focusable = false
}},
This works insofar as now, I cannot put the focus on the xfpanel client using keyboard conrtrols.
However, when I click somewhere on the xfpanel (e.g., open the whisker menu, or click on the NetworkManager applet, ...), Awesome makes xfpanel the focused client.
I don't like this behavior because it means I have to explicitly shift focus back to where I was working before.
Is there a way to prevent awesome from changing focus when a mouse click
occurs?
If you don't want the default settings for docks, make that rule ignore "dock" clients. With this I mean: Find the awful.rules-rule with rule = {}, and change this into rule = {}, except = { type = "dock" },.
Since this default rule sets up button bindings (buttons = clientbuttons), this means that dock-clients will no longer get these button bindings.

how to change dynamic button background color

I have programmatically created buttons, want to change color when button clicked, For example if a button clicked change the color to red, another button clicked means change back to default
I created button using
for var i=0 ;i<=8;i++{
var button = UIButton(..)
........... blah blah......
button.addTarget(..,action:"buttonsClick",...)
}
fun buttonsClick(sender:UIButton){
// here how to identify which button is clicked and change color to red if another is clicked means change to default color
var tagnum = sender.tag
}
Or another solution available for this
I got that output from another discussion in the stackoverflow
create a function
func Changecolor(sender:UIButton){
if sender.backgroundColor == UICcolor.graycolor() {
sender.backgroundColor = UIColor.redcolor()
}
else
{
sender.backgroundColor = UIColor.graycolor()
}
This function called in
button.addTarget(blah,selector:"Changecolor:",forControlEvents:UIControlEvents.AllEvents)

Resources