How do I set an application's taskbar icon in PyQt4?
I have tried setWindowIcon, and it successfully sets the icon in the top-left of the main window, but it does not affect the icon shown in the Windows 7 taskbar -- the taskbar icon remains the default Python pyw icon. Here is my code:
from PyQt4 import QtGui
app = QtGui.QApplication([])
mainwindow = QtGui.QMainWindow()
mainwindow.show()
app.setWindowIcon(QtGui.QIcon('chalk.ico'))
mainwindow.setWindowIcon(QtGui.QIcon('chalk.ico'))
app.exec_()
[update] I've tried placing the setWindowIcon() before the show(). I've tried it with other images, ico and png. Nothing helps.
I've found the answer, after some digging.
In Windows 7, the taskbar is not for "Application Windows" per se, it's for "Application User Models". For example, if you have several different instances of your application running, and each instance has its own icon, then they will all be grouped under a single taskbar icon. Windows uses various heuristics to decide whether different instances should be grouped or not, and in this case it decided that everything hosted by Pythonw.exe should be grouped under the icon for Pythonw.exe.
The correct solution is for Pythonw.exe to tell Windows that it is merely hosting other applications. Perhaps a future release of Python will do this. Alternatively, you can add a registry key to tell Windows that Pythonw.exe is just a host rather than an application in its own right. See MSDN documentation for AppUserModelIDs.
Alternatively, you can use a Windows call from Python, to explicitly tell Windows what the correct AppUserModelID is for this process:
import ctypes
myappid = 'mycompany.myproduct.subproduct.version' # arbitrary string
ctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID(myappid)
EDIT: Please see Ronan's answer: the myappid string should be unicode.
#DamonJW's answer will work, but there is a minor catch: myappid should be unicode (argument type is PCWSTR).
import ctypes
myappid = u'mycompany.myproduct.subproduct.version' # arbitrary string
ctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID(myappid)
Otherwise getting the AppUserModelID will get wrong unicode characters (祭潣灭湡祭牰摯捵畳灢潲畤瑣瘮牥楳湯):
import ctypes
from ctypes import wintypes
lpBuffer = wintypes.LPWSTR()
AppUserModelID = ctypes.windll.shell32.GetCurrentProcessExplicitAppUserModelID
AppUserModelID(ctypes.cast(ctypes.byref(lpBuffer), wintypes.LPWSTR))
appid = lpBuffer.value
ctypes.windll.kernel32.LocalFree(lpBuffer)
if appid is not None:
print(appid)
That said, it is a minor thing, since Windows will still recognize the unicode string as "another process" and switch the icon accordingly.
You must set the AppUserModelID before your app shows any GUI. If you need to access other Windows 7 features you can have a look at Q7Goodies which is a Qt add-on for Windows 7 with a PyQt bindings.
Related
I have a PySide app that needs to run as admin. I've used a technique recommended by this post.
import os
import sys
import time
from PySide.QtGui import *
from win32com.shell import shellcon
import win32com.shell.shell as shell
import win32con
def force_elevated():
try:
if sys.argv[-1] != 'asadmin':
script = os.path.abspath(sys.argv[0])
params = ' '.join([script] + sys.argv[1:] + ['asadmin'])
shell.ShellExecuteEx(nShow=win32con.SW_SHOWNORMAL,
fMask=shellcon.SEE_MASK_NOCLOSEPROCESS,
lpVerb='runas',
lpFile=sys.executable,
lpParameters=params)
sys.exit()
except Exception as ex:
print ex
class MyGui(QWidget):
def __init__(self):
super(MyGui, self).__init__()
self.show()
app = QApplication(sys.argv)
force_elevated()
splash = QSplashScreen("logo.png")
splash.show()
time.sleep(2)
gui = MyGui()
app.exec_()
Windows UAC pops up and asks the user to allow admin rights. If the user selects yes, a new instance of the application starts up in admin mode. If the user selects no, the try statement fails, and the program continues to run in non-admin mode.
The problem is, when running in non-admin mode, the application starts up behind other windows, so it's easy to think it's not running at all. After using cx_freeze to make an executable, it can also happen even when you do activate admin mode.
I can't have the window always be on top. I've tried temporarily setting it as always on top (to bring it to front) and then turn it off, but this does not work. I've also tried using various libraries and built in functions to locate the process ID and tell windows to bring it to front. They either haven't worked at all, or don't work reliably.
Does anyone have a reliable way to make sure the PySide window appears on top?
You can bring the window to the front with gui.raise_()
I thought that in the 21st century this is not a problem, but:
import sys
from PySide import QtGui
print('\u2122')
app = QtGui.QApplication(sys.argv)
widget = QtGui.QWidget()
widget.setWindowTitle('\u2122')
widget.show()
sys.exit(app.exec_())
on Ubuntu displays the trademark symbol in both the window and the terminal, on Windows (10) it displays \u2122 both places. I am using python 3.4 on both systems, on windows it's an Canopy install, if that helps anything, but probably totally unrelated to that. How can I get unicode characters to display on Windows as well?
EDIT
Okay, so it turned out that having print() doesn't make it python 3, my bad. Although the Windows python 2.7.9 gives an interesting error when I fix the strings to u'\u2122:
File "C:\Program Files\Enthought\Canopy32\App\appdata\canopy-1.5.5.3123.win-x86\lib\encodings\cp852.py", line 12, in encode
return codecs.charmap_encode(input,errors,encoding_map)
UnicodeEncodeError: 'charmap' codec can't encode character u'\u2122' in position 0: character maps to <undefined>
Anyway, installing a 3.x will solve the issue.
Ensure that you have Python 3.x on your Windows box. The results are consistent with using Python 2.x.
To make your code with 2.x, change the strings into Unicode strings by appending a u to each one. E.g.
widget.setWindowTitle('\u2122')
On Windows, don't try to print Unicode to the console - it's totally broken. If you must, see the following module which allows it: https://github.com/Drekin/win-unicode-console
Qt version 4.8.1, building for Windows, I'm trying to get accessibility information to work correctly for some buttons I have.
I have a QPushButton in my main window, which has an icon, thusly:
m_restartBtn = new QPushButton();
QPixmap rpm(":/images/Restart32x32.png");
QIcon ricn(rpm);
m_restartBtn->setIcon(ricn);
m_restartBtn->setIconSize(rpm.rect().size());
// put it in a box in the main layout
QHBoxLayout *buttonBox = new QHBoxLayout;
ui->mainLayout->addLayout(buttonBox);
buttonBox->addWidget(m_restartBtn);
Now that button shows up correctly, and if I hook up the signals it works fine. But when I use the 'inspect.exe' (from the Win 7 SDK), I see that the button shows up, but has no name.
If I use setText instead of putting in an icon, the accessible name shows up correctly, but of course, I'm seeing text, not my icon. If I do both, then the accessible name works fine, but I get the text on screen, as one would expect.
I tried setObjectName and setWindowTitle just for laughs, and they of course didn't work.
Is there a proper way to set the accessible name for a QPushButton that only displays an icon?
My immediate goal is to remotely control the application for accessibility purposes. But I'd like the work to do double duty and get me full accessibility at the same time, so I don't have to do a separate effort later for accessibility.
You can use QWidget::setAccessibleName(const QString &name).
QPushButton *button = new QPushButton(this);
button->setAccessibleName("name");
Is this what you were looking for?
I have same user logged in into windows 7 station with several simultaneous sessions (like Concurrent RDP or log in at station and then via RDP).
UPDATE:
Ok, my research in this question has been stuck at this point (python example to write less complicated code):
#!/usr/bin/env python
import ctypes
import ctypes.wintypes as wintypes
def enum_desktops():
GetProcessWindowStation = user32.GetProcessWindowStation
EnumDesktops = user32.EnumDesktopsW
EnumDesktopsProc = ctypes.WINFUNCTYPE(wintypes.BOOL, wintypes.LPWSTR, wintypes.LPARAM)
hwinsta = GetProcessWindowStation()
def foreach_desktop(desk_name, lparam):
print("Desktop %s"%desk_name)
return True
EnumDesktops(hwinsta, EnumDesktopsProc(foreach_desktop), desk_lparam)
This function prints information about "Default" and "Winlogon" dektops. If we try to enumerate window stations, we'll get only "WinSta0", while I can see potentially target process started on different logon session.
So, what should I use to find window for target Desktop?
daemon is not an option at this point at all.
Have a background app or task tray applet that gets launched with every desktop session. (Easily installed by adding an EXE path to the following registry key: HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\Current Version\Run).
The code that lives in that installed application will do two things:
All the desktop windows enumeration and manipulation that you need to do that can only interact with the local desktop.
Acts as a "Client" to your "server" app that runs on another desktop session. Your server app is what triggers the clients to do the window scanning. You can use almost any interprocess communication mechanism you want for this.
Already some time passed from the time the question was posted, but in case someone needs it, I will post an answer.
What you have to do is set a desktop for your current thread, which is calling FindWindow. In this way, your calling thread will operate in other desktop and will find a window. For this to achieve, you have to use SetThreadDesktop WinAPI function.
For more info, check MSDN documentation on SetThreadDesktop.
In a windows version with tablet support, a small keyboard icon appears when an edit control gets focus. If you touch it the touch keyboard pops up.
Is there a way to disable this? It's rather inconvenient if you have your own touch keyboard.
I want to disable it for certain edit controls in code, ie. I'm not looking for a Windows setting.
Giel
Well, I guess a late answer is better than no answer, so here it comes:
You can disable the Windows onscreen-keyboard for your application.
To do so, start Regedit and navigate to the Key [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\TabletTIP\DisableInPlace]. There you create a new String Value, set its name to the full application Path (e.g. "C:\Progam Files\My App\MyApp.exe") and set its value to "1".
Edit: Recently I had to rethink my solution... By setting the Registry value, you disable the onscreen-keyboard for the whole application. But should you need a keyboard for some seldom used function of your program and just happend to forget including an onscreen-keyboard, you have to control the Windows TextInputPanel via SDK / API. See this link: Disabling the Input Panel Programmatically.
Use the PenInputPanel for handwriting and the TextInputPanel for an onscreen-keyboard.
For all those Delphi programmers out there: import the Type Library "Microsoft PenInputPanel" and FIX A BUG in the imported *_TLB.pas: change the parameter type of the two methods of IPenInputPanel:
function Get_AttachedEditWindow: SYSINT; safecall;
procedure Set_AttachedEditWindow(AttachedEditWindow: SYSINT); safecall;
Disable the "Touch Keyboard and Handwriting Panel Service"