The following code sample works under linux (ubuntu) and Windows XP, but not under OSX.
import wx
class frame(wx.Frame):
def __init__(self,p=None):
wx.Frame.__init__(self,p)
self.box = wx.ListBox(self)
self.box.AppendItems( ["Zero","One","Two","Three","Four","Five","Six"])
self.box.Bind(wx.EVT_MOUSE_EVENTS,self.onMouse)
def onMouse(self,evt):
pos = evt.GetPosition()
print self.box.HitTest(pos)
evt.Skip()
class guiApp(wx.App):
def __init__(self,redirect=False):
wx.App.__init__(self,redirect)
def OnInit(self):
f = frame()
f.Show()
self.SetTopWindow(f)
return True
if __name__=="__main__":
app = guiApp()
app.MainLoop()
On Linux and Windows, the correct items are identified when moused over. On OSX hittest always returns -1 (wx.NOT_FOUND)
I'm running 32-bit wxPython, 2.8.12.1 (mac-unicode) which uses the Carbon API in 32bit python 2.7.2.
I can't find this listed as a known bug in wxWidgets and I'm hesitant to submit as it seems this should work. The listbox control is deeply integrated into out GUI and I really don't want to swap it out for ListCtrl or something similar as we have all other functionality working now. Does anyone know a workaround?
There is no work around if the listbox is scrolling. The scroll is handled be the underlying Carbon library and scroll position is not accurately reported back through wx.
I found the bug in the wxWidgets source code and opened a ticket on the wxWidgets trac, http://trac.wxwidgets.org/ticket/13699, with a patch.
The root of the bug is a call to the Mac's underlying DataBrowser with an incorrect rowId argument. wxWidgets was passing row position offsets, assuming this would be the rowId's (and maybe at some point apple used these internally when true Id's weren't specified.) Adding a call to another function translates a row's position (offset) into it's real id. With a patched version of wxWidgets the above script works as expected.
Related
I'm creating a GUI with PyQt4 for my bachelor thesis. I have a QComboBox, where every item is a checkbox. Here is my code:
somewhere in the constructor:
self.multi = QtGui.QComboBox(self)
self.multi.setEnabled(True)
self.multi.view().pressed.connect(self.handleItemPressed)
and here I fill the QComboBox with my checkboxes:
def fillMultiCombo(self):
# len(self.featureNames) rows, 1 column
model = QtGui.QStandardItemModel(len(self.featureNames), 1)
firstItem = QtGui.QStandardItem("feature(s)")
firstItem.setBackground(QtGui.QBrush(QtGui.QColor(200, 200, 200)))
firstItem.setSelectable(False)
model.setItem(0, 0, firstItem)
for i,query in enumerate(self.featureNames):
item = QtGui.QStandardItem(query)
item.setFlags(QtCore.Qt.ItemIsEnabled)
item.setData(QtCore.Qt.Unchecked, QtCore.Qt.CheckStateRole)
model.setItem(i+1, 0, item)
self.multi.setModel(model)
Just to say in advance: I think it's not a code issue, but I provided some code to make it clearer.
The problem now is: On Windows 7 (on 2 different machines) it all works fine. But on my tutor's machine (Macbook Pro, I don't know which OS sorry), the checkboxes are not showing (but no error or warning printed), BUT when you click it, the checkbox is checked. So it's like the checkbox is there and functions, but it is invisible.
So is this a bug, machine dependent or some other issue. Because all other things work on her machine totally smooth.
After a long time I've finally found the problem. Here is the important code snippet:
app = QtGui.QApplication(sys.argv)
# Available styles (depending on the OS) for my ThinkPad:
# Windows
# WindowsXP
# WindowsVista
# Motif
# CDE
# Plastique
# Cleanlooks
# makes the split bar visible
app.setStyle(QtGui.QStyleFactory.create('Plastique'))
So before I set the style for my application, Qt chose the most appropriate style depending on the plattform resp. OS. So the default style Qt chose for my machine worked and the checkboxes are normally shown. The default style Qt chose for the application on the machine from my tutor was not the same. In fact if I change from 'Plastique' to 'Cleanlooks' my checkboxes also disappear.
I'm new to PyQt. I have been searching on how to find the window of my PyQt app which is currently open and bring it to the front. This far all I've found is an example in which pywin32 was used(thus windows specific). I wanted to ask if there is a platform-independent way I can achieve the objective. Any help would be much appreciated.
Here is my code. The activateWindow() function is supposed to bring it to the front.
class TestApp(QtGui.QApplication):
def __init__(self, argv, key):
QtGui.QApplication.__init__(self, argv)
self._activationWindow=None
self._memory = QtCore.QSharedMemory()
self._memory.setKey(key)
if self._memory.attach():
self._running = True
else:
self._running = False
if not self._memory.create(1):
raise RuntimeError(
self._memory.errorString().toLocal8Bit().data())
def isRunning(self):
return self._running
def activationWindow(self):
return self._activationWindow
def setActivationWindow(self, activationWindow):
self._activationWindow = activationWindow
def activateWindow(self):
if not self._activationWindow:
return
self._activationWindow.setWindowState( self._activationWindow.windowState() & ~QtCore.Qt.WindowMinimized | QtCore.Qt.WindowActive)
self._activationWindow.raise_()
self._activationWindow.show()
self._activationWindow.activateWindow()
A complete, platform-indepenent solution is probably going to be beyond reach. Each of the platforms supported by Qt behaves in a different way, and activateWindow seems to be somewhat buggy.
To start with, here's what the Qt docs say about activateWindow:
This function performs the same operation as clicking the mouse on the
title bar of a top-level window. On X11, the result depends on the
Window Manager. If you want to ensure that the window is stacked on
top as well you should also call raise(). Note that the window must be
visible, otherwise activateWindow() has no effect.
and:
On Windows, if you are calling this when the application is not
currently the active one then it will not make it the active window.
It will change the color of the taskbar entry to indicate that the
window has changed in some way. This is because Microsoft does not
allow an application to interrupt what the user is currently doing in
another application.
For more confirming evidence of the difficulties, take a look at these threads on the Qt forum:
Bring window to front -> raise(), show(), activateWindow() don’t work on Windows
activateWindow() does not send window to front
I am writing some code where I need to drop down from GTK+ to Xlib. Specifically, I would like to set the icon of a toplevel window to be a window itself, rather than a pixmap, in order to write a GTK+ Window Maker dockapp.
I got this to work in C as follows:
gdkDockapp = gtk_widget_get_window(dockapp);
xDockapp = GDK_WINDOW_XID(gdkDockapp);
gdkDisplay = gdk_window_get_display(gdkDockapp);
xDisplay = GDK_DISPLAY_XDISPLAY(gdkDisplay);
wmhints.icon_window = xDockapp;
wmhints.flags = IconWindowHint;
XSetWMHints(xDisplay, xDockapp, &wmhints);
However, I am hoping to actually code my application in Python. When I try to convert the code, e.g.,
gdkDockapp = dockapp.get_window()
xDockapp = gdkDockapp.get_xid()
a long is returned rather than a Window, so I can't perform any of the Xlib functions. Any suggestions?
You can get Xlib.Display.Window object with this function: d.create_resource_object("window", xid), where d is Xlib.display.Display object.
Not sure using Xlib is a wise move in times where the X server is meant to disappear in favor of a Wayland compositor.
The following bit of code populates a class that inherits from the wx.Menu class, with menu items. So self is basically a wx.Menu. When I run the flowing code snippet, the line about.SetBitmap(wx.Bitmap('Icon24.ico')) seems to change the highlighting from the default:
to this plain blue style:
The line about.SetBitmap(wx.Bitmap('Icon24.ico')) simply adds an icon (test). But, for some reason it changes the highlighting style. I know this is about as nitpicky as it gets, but I'd like to the first images highlighting style with the second images Icon. This is in Windows 7 if it makes a difference.
Snippet:
about = wx.MenuItem(self, -1, 'About...')
about.SetBitmap(wx.Bitmap('Icon24.ico')) # The line that's causing the problem.
itemlist = [self.AppendItem(about),
self.AppendSeparator(),
self.Append(-1, 'Options...'),
self.AppendSeparator(),
self.Append(-1, 'Exit')]
for i in itemlist:
self.Bind(wx.EVT_MENU, self.menu_beh, i)
Well, according to the WxWidgets doc, the version 2.8 doesn't support Windows Vista or 7, so I think this is expected since looks like it reset the entire menu theme to the XP style, I think the best you can try is to use the testing version 2.9, which support Vista (but not 7).
I need to get focus to a specified window, and the only way I'm seeing on my head, is minimizing all windows on front of it until I get the right one...
How can I do it?
Windows 7, and no specific toolkit....
Every type of window, for example, firefox and console command
You'll need to enumerate through the windows and match the title of the window to get the one you want. The code below searches for a window with "firefox" in the title and sets the focus:
import win32gui
toplist = []
winlist = []
def enum_callback(hwnd, results):
winlist.append((hwnd, win32gui.GetWindowText(hwnd)))
win32gui.EnumWindows(enum_callback, toplist)
firefox = [(hwnd, title) for hwnd, title in winlist if 'firefox' in title.lower()]
# just grab the first window that matches
firefox = firefox[0]
# use the window handle to set focus
win32gui.SetForegroundWindow(firefox[0])
To minimize the window, the following line:
import win32con
win32gui.ShowWindow(firefox[0], win32con.SW_MINIMIZE)
You'll need to enumerate through the windows and match the title of the window to get the one you want. The code below searches for a window with "firefox" in the title and sets the focus
To minimize the window use the following line:
def enumHandler(hwnd, lParam):
if 'firefox' in win32gui.GetWindowText(hwnd):
win32gui.ShowWindow(hwnd, win32con.SW_MINIMIZE)
win32gui.EnumWindows(enumHandler, None)
This works for Windows 10, Python3.5 32bit, pywin32‑223.
I reported the above case, but an error occurred.
Traceback (most recent call last):
TypeError: The object is not a PyHANDLE object
I'm assuming from the question, that you want to write a generic to that can work with any window from any application.
You might want to try the Python Win32 GUI Automation library. I haven't used it but sounds like it might be what you are looking for. If that doesn't work, your best option might be forgo python and use a tool like AutoIt that provides built in support for window manipulation.
If neither of those solutions work you will probable have to directly invoke windows api. I do not know if the win32api package wraps the necessary functionality, otherwise you will have write a python module in c/c++.
If this kind of functionality is available in the .net api, you could use IronPython.