PyQt4 QComboBox Signals and Slots - python

is there a way to create a signal that asserts when a combo box is opened and user uses the up - down arrows on the keyboard to select an item. So far the Qt4 reference lists signals that activate only after a mouse click or return key hit. I tried highlighted(int) and that only worked with another mouse click but when i use the up/down arrows, only the first item that was clicked is retrieved. I thought the current highlighted index is the one that is returned via self.ui.cb_dspBenchCmds.currentText().
here's a code snippet:
class CmdRef(Qg.QMainWindow):
def __init__(self,parent = None):
........
Qc.QObject.connect(self.ui.cb_dspBenchCmds, Qc.SIGNAL("activated(int)"), self.chooseCmd)
........
def chooseCmd(self):
whichCmd = self.ui.cb_dspBenchCmds.currentText()
cmdDescription = self.dictDspCmds[str(whichCmd)]
self.ui.te_dspBenchOutput.setText(''.join(cmdDescription))
thanks
dave

The highlighted signal does appear to be the one you want.
You just need to make use of the passed value:
class CmdRef(Qg.QMainWindow):
def __init__(self, parent = None):
...
self.ui.cb_dspBenchCmds.highlighted['QString'].connect(self.chooseCmd)
...
def chooseCmd(self, whichCmd):
cmdDescription = self.dictDspCmds[str(whichCmd)]
self.ui.te_dspBenchOutput.setText(''.join(cmdDescription))

Related

Providing right-click context menu for a separate program using wxPython

I was having trouble formatting the title of this question, because I wasn't sure I'm going about this the right way, so let me explain.
I want to try and add a right-click context menu to an existing program for which I don't have the source code. wxPython is generally my framework of choice. I figured there was a couple ways of doing this:
1) Create a transparent wx.Frame which is tied to and sits on top of the existing program, intercepting mouse events. If I did this, I wasn't sure if the mouse events could then be passed to the underlying window. I like this option, because it would allow adding more useful information in the overlay.
2) Create a headless program which globally intercepts right-click events, and spawns the context menu at the pointer location when certain conditions are met. Based on the research I've done so far, this didn't seem possible without continuously polling for mouse position.
What am I missing? Is there a more elegant solution for this? Is this even possible using Python?
edit: I have a partial proof-of-concept working which looks like this:
import wx
import win32gui
import win32api
import win32con
class POC_Frame(wx.Frame):
def __init__(self, parent):
wx.Frame.__init__(self, parent, id=wx.ID_ANY, title='POC', pos=(0,0), size=wx.Size(500, 500), style=wx.DEFAULT_FRAME_STYLE)
self.ToggleWindowStyle(wx.STAY_ON_TOP)
extendedStyleSettings = win32gui.GetWindowLong(self.GetHandle(), win32con.GWL_EXSTYLE)
win32gui.SetWindowLong(self.GetHandle(), win32con.GWL_EXSTYLE,
extendedStyleSettings | win32con.WS_EX_LAYERED | win32con.WS_EX_TRANSPARENT)
win32gui.SetLayeredWindowAttributes(self.GetHandle(), win32api.RGB(0,0,0), 100, win32con.LWA_ALPHA)
self.Bind(wx.EVT_RIGHT_DOWN, self.onRightDown)
self.Bind(wx.EVT_RIGHT_UP, self.onRightUp)
self.CaptureMouse()
def onRightDown(self, event):
print(event)
def onRightUp(self, event):
print(event)
app = wx.App(False)
MainFrame = POC_Frame(None)
MainFrame.Show()
app.MainLoop()
This seems to work OK, as it passes the right click events to the underlying window, while still recognizing them, but it only does it exactly once. As soon as it loses focus, it stops working and nothing I've tried to return focus to it seems to work.
I've always had better luck hooking global mouse and keyboard events with pyHook rather than wx. Here is a simple example:
import pyHook
import pyHook.cpyHook # ensure its included by cx-freeze
class ClickCatcher:
def __init__(self):
self.hm = None
self._is_running = True
self._is_cleaned_up = False
self._is_quitting = False
self.set_hooks()
# this is only necessary when not using wx
# def send_quit_message(self):
# import ctypes
# win32con_WM_QUIT = 18
# ctypes.windll.user32.PostThreadMessageW(self.pump_message_thread.ident, win32con_WM_QUIT, 0, 0)
def __del__(self):
self.quit()
def quit(self):
if not self._is_running:
return
self._is_quitting = True
self._is_running = False
if self.hm:
# self.hm.UnhookKeyboard()
self.hm.UnhookMouse()
# self.send_quit_message()
self._is_cleaned_up = True
def set_hooks(self):
self._is_running = True
self._is_cleaned_up = False
self.hm = pyHook.HookManager()
self.hm.MouseRightUp = self.on_right_click
# self.hm.HookKeyboard()
self.hm.HookMouse()
def on_right_click(self):
# create your menu here
pass
If you weren't using wx, you'd have to use pythoncom.PumpMessages to push mouse and keyboard events to you program, but App.Mainloop() accomplishes the same thing (if you use PumpMessages and Mainloop together about half of the events won't be push to your program).
Creating a wx.Menu is easy enough. You can find the mouse coordinates using wx.GetMousePosition()

How to choose line-edit according to which button was clicked

I have two buttons (Eg. A andB) which do the same things (based on user selection). So when you select something, then click the button, the selection's name will be input into the line-edit for the button. For example, if I click on buttonA, the input will be to lineEditA.
Currently I have created a signal function as follows:
def _connections_setup(self):
self.btnA.clicked.connect(self.get_sel_nameA)
self.btnB.clicked.connect(self.get_sel_nameB)
def get_sel_nameA(self):
sel_name = get_name_from_sel()
self.line_editA.setText(sel_name)
def get_sel_nameB(self):
sel_name = get_name_from_sel()
self.line_editA.setText(sel_name)
"""
def get_sel_name(self):
# Returns me a blank
button = self.sender()
print button.objectName()
# My objective here would be, if btnA is clicked, the sel_name will be inputted into lineEditA. Likewise for btnB
"""
Instead of creating two similar functions, how can I determine which button was clicked and have the selection's name to be input correctly into the line-edit?
I tried using self.sender() (see get_sel_name()) but it does not seems to return me the button name.
The sender() function only works in slots directly connected to signals. So your code needs to look something like this:
def _connections_setup(self):
self.btnA.clicked.connect(self.get_sel_name)
self.btnB.clicked.connect(self.get_sel_name)
def get_sel_name(self):
button = self.sender()
name = button.objectName()
if button is self.btnA:
self.line_editA.setText(name)
elif button is self.btnB:
self.line_editB.setText(name)

pyqt: add clicked event for a Qlabel

I've created label: self.labelOnlineHelp = QLabel('Online Help') and want to make it clickable. Ideally it should open firefox (but not a default browser) and also change mouse to pointer (in a nutshell: just to create an usual hyperlink). I see that there is no clicked event in qlabel. Is there any way how to perform this in a simple way?
You can do this using setOpenExternalLinks
self.labelOnlineHellp.setOpenExternalLinks(True)
If you want to do something different than the default behavior (ie. open link in the default browser), you can connect to the linkActivated signal instead (don't use setOpenExternalLinks to True if you're handling the opening of the link yourself).
self.labelOnlineHelp.linkActivated.connect(self.link_handler)
def link_handler(self, link):
subprocess.call(['/path/to/firefox', link])
You need to reimplement QLabel class and override the mousePressEvent or mouseReleaseEvent. Here is a simple example:
class MyLabel(QLabel):
def __init__(self, parent):
QLabel.__init__(self, parent)
self.link = "http://www.example.com"
def mousePressEvent(self, event):
# open the link on your browser
webbrowser.get('firefox').open_new_tab(self.link)

Tkintertable Get selected Data

I'm using tkintertable and want to check which row is selected. Is this possible?
And I also want to sort the columns and name the columns like I want...
How can I do this?
I'm a little late, but figured I would answer this in case anyone else finds this through a google search like I did :P
There are a couple ways to do select data based on mouse clicks.
First you need to bind the mouse click to a callback function, and in this callback function you need to grab the data. You might need to bind the mouse click on release so that it grabs data when you release the mouse button.
You can use the table.get_row_clicked()/table.get_col_clicked() functions along with model.getValueAt() to do get individual cells.
To get the contents of an entire row in a dictionary where column_name = key & contents of that selected rows column = value, you need to use model.getRecordAtRow(row_index).
Example:
from Tkinter import *
from ttk import *
from tkintertable.Tables import TableCanvas
from tkintertable.TableModels import TableModel
class Application(Frame):
def __init__(self, master=None):
Frame.__init__(self, master)
self.pack()
self.model = TableModel()
self.table = TableCanvas(self, model=self.model)
self.table.createTableFrame()
root.bind('<ButtonRelease-1>', self.clicked) #Bind the click release event
self.create_widgets()
def create_widgets(self):
self.table.model.load('save.table') #You don't have to load a model, but I usually
self.table.redrawTable() #Create a base model for my tables.
d = dir(self.table) #Will show you what you can do with tables. add .model
#to the end to see what you can do with the models.
for i in d:
print i
def clicked(self, event): #Click event callback function.
#Probably needs better exception handling, but w/e.
try:
rclicked = self.table.get_row_clicked(event)
cclicked = self.table.get_col_clicked(event)
clicks = (rclicked, cclicked)
print 'clicks:', clicks
except:
print 'Error'
if clicks:
#Now we try to get the value of the row+col that was clicked.
try: print 'single cell:', self.table.model.getValueAt(clicks[0], clicks[1])
except: print 'No record at:', clicks
#This is how you can get the entire contents of a row.
try: print 'entire record:', self.table.model.getRecordAtRow(clicks[0])
except: print 'No record at:', clicks
root = Tk()
root.title('Table Test')
app = Application(master=root)
print 'Starting mainloop()'
app.mainloop()
As far as the other things, you should be able to get info off the wiki:
http://code.google.com/p/tkintertable/wiki/Usage
Some things are a pain to figure out, but it's worth it IMO. I still can't figure out how to programmatically change the contents of a cell, and that's right on the wiki page, lol.

How can I handle a mouseMiddleDrag event in PythonCard?

I would like to use the middle mouse button to drag an image in an application written in Python and using PythonCard/wxPython for the GUI.
The latest version of PythonCard only implements a "left mouse button drag" event and I am trying to modify PythonCard to handle a "middle mouse button drag" as well.
Here is the relevant code from Lib\site-packages\PythonCard\event.py :
class MouseMoveEvent(MouseEvent, InsteadOfTypeEvent):
name = 'mouseMove'
binding = wx.EVT_MOTION
id = wx.wxEVT_MOTION
def translateEventType(self, aWxEvent):
if aWxEvent.Dragging():
return MouseDragEvent.id
else:
return self.id
class MouseDragEvent(MouseMoveEvent):
name = 'mouseDrag'
id = wx.NewEventType()
class MouseMiddleDragEvent(MouseMoveEvent): #My addition
name = 'mouseMiddleDrag'
id = wx.NewEventType()
My addition does not work. What can I do instead? Is there a specific wxPython method that I could use to bypass PythonCard?
It turns out the the mouseDrag event is active regardless of which button on the mouse is pressed. To filter the middle mouse button, you need to call the MiddleIsDown() method from the MouseEvent.
def on_mouseDrag( self, event ):
do_stuff()
if event.MiddleIsDown():
do_other_stuff()

Categories