How to create an alert box without using Tkinter? - python

I need to create a message box in python without using python Tkinter library so that I can use that before using exit() function this will display the message and answer as soon as user presses okay, user gets out of program.

Here's one way to do it with Windows' msg command. The code is based on #ErykSun's comment under the question Can't execute msg (and other) Windows commands via subprocess.
import os
import subprocess
sysroot = os.environ['SystemRoot']
sysnative = (os.path.join(sysroot, 'SysNative')
if os.path.exists(os.path.join(sysroot, 'SysNative'))
else
os.path.join(sysroot, 'System32'))
msgexe_path = os.path.join(sysnative, 'msg.exe')
subprocess.run([msgexe_path, '*', 'ALL YOUR BASE ARE WHERE BELONG TO US.'])

Related

Python Windows Explorer Refresh PostMessage

I'm writing a Python script to toggle the "Hidden Items" status of the Windows Explorer. It changes the value of Computer\HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Advanced\Hidden, but for the change to take effect all instances of the Explorer have to be refreshed.
I implemented the same idea a few months ago with AutoHotkey, there I could solve the refresh problem with the following commands I found on the AutoHotkey Forum:
WinGetClass, CabinetWClass
PostMessage, 0x111, 28931, , , A
PostMessage, 0x111, 41504, , , A
I tried different approaches to translate it, but wasn't able to get it working with Python. While searching for an answer I also found a solution with C# (Refresh Windows Explorer in Win7), which is far more complicated than the AutoHotkey version. I could let the Python script call the C# script, but I would much prefer a solution without auxiliary files.
How can I implement such behavior with Python?
Using pywin module:
import win32con
import win32gui
# List for handles:
handles = []
def collect_handles(h, _):
' Get window class name and add it to list '
if win32gui.GetClassName(h) == 'CabinetWClass':
handles.append(h)
def refresh_window(h):
' Send messages to window '
win32gui.PostMessage(h, win32con.WM_COMMAND, 28931, None)
win32gui.PostMessage(h, win32con.WM_COMMAND, 41504, None)
# Fill our list:
win32gui.EnumWindows(collect_handles, None)
# Perform action on our handles:
list(map(refresh_window, handles))

Create a MessageBox in Python for Mac?

Currently working through a free online class for Python from Cybrary (I'm coding in 3.6), but I use a Mac while the presenter uses Windows. So far, there have been very few differences if any.
The current section deals with learning and using Ctypes however, and the "assignment" says to Write a function which takes two arguments, title and body and creates a MessageBox with those arguments.
The code used in the video as an example of creating a Message Box:
from ctypes import *
windll.user32.MessageBoxA(0, "Click Yes or No\n", "This is a title\n", 4)
My code:
# 2.1 Ctypes: Write a function which takes two arguments, title and body
# and creates a MessageBox with those arguments
def python_message_box(title, body):
return windll.user32.MessageBoxA(0, body, title, 0)
Running this gives the error:
File ".../AdvancedActivities.py", line 9, in python_message_box
return windll.user32.MessageBoxA(0, body, title, 0)
NameError: name 'windll' is not defined
I don't believe I need to say that I get the same error trying to run
windll.user32.MessageBoxW(0, body, title, 0)
I haven't been able to find any examples anywhere of people creating Message Boxes on Mac computers. Is it a Windows-specific function? If so, what would be the Mac equivalent of this?
EDIT: Mark Setchell's solution is to have Python run terminal functions that accomplish windll tasks, so instead of windll.user32.MessageBoxA(0, body, title, 0), use:
command = "osascript -e 'Tell application \"System Events\" to
display dialog \""+body+"\"'"
system(command)
If you type this into a Terminal on any Mac, you'll get a dialog box:
osascript -e 'Tell application "System Events" to display dialog "Some Funky Message" with title "Hello Matey"'
See here for further examples.
So, just use a Python subprocess call to run that... subprocess documentation, or use system().
Nothing to install. No dependencies. You can also ask user for values, select files or directories and pick colours using the same technique. The dialog boxes are all native Mac ones - not some ugly imitation.
import os
body_Str="Body of Dialog"
title_Str="Title"
os.system("""osascript -e \'Tell application \"System Events\" to display dialog \""+body_Str+"\" with title \""+title_Str+"\"\'""")
this is much better

Is there a way to open a text file into python code (similar to doing CTRL+O on windows)? [duplicate]

I have a simple script which parses a file and loads it's contents to a database. I don't need a UI, but right now I'm prompting the user for the file to parse using raw_input which is most unfriendly, especially because the user can't copy/paste the path. I would like a quick and easy way to present a file selection dialog to the user, they can select the file, and then it's loaded to the database. (In my use case, if they happened to chose the wrong file, it would fail parsing, and wouldn't be a problem even if it was loaded to the database.)
import tkFileDialog
file_path_string = tkFileDialog.askopenfilename()
This code is close to what I want, but it leaves an annoying empty frame open (which isn't able to be closed, probably because I haven't registered a close event handler).
I don't have to use tkInter, but since it's in the Python standard library it's a good candidate for quickest and easiest solution.
Whats a quick and easy way to prompt for a file or filename in a script without any other UI?
Tkinter is the easiest way if you don't want to have any other dependencies.
To show only the dialog without any other GUI elements, you have to hide the root window using the withdraw method:
import tkinter as tk
from tkinter import filedialog
root = tk.Tk()
root.withdraw()
file_path = filedialog.askopenfilename()
Python 2 variant:
import Tkinter, tkFileDialog
root = Tkinter.Tk()
root.withdraw()
file_path = tkFileDialog.askopenfilename()
You can use easygui:
import easygui
path = easygui.fileopenbox()
To install easygui, you can use pip:
pip3 install easygui
It is a single pure Python module (easygui.py) that uses tkinter.
Try with wxPython:
import wx
def get_path(wildcard):
app = wx.App(None)
style = wx.FD_OPEN | wx.FD_FILE_MUST_EXIST
dialog = wx.FileDialog(None, 'Open', wildcard=wildcard, style=style)
if dialog.ShowModal() == wx.ID_OK:
path = dialog.GetPath()
else:
path = None
dialog.Destroy()
return path
print get_path('*.txt')
pywin32 provides access to the GetOpenFileName win32 function. From the example
import win32gui, win32con, os
filter='Python Scripts\0*.py;*.pyw;*.pys\0Text files\0*.txt\0'
customfilter='Other file types\0*.*\0'
fname, customfilter, flags=win32gui.GetOpenFileNameW(
InitialDir=os.environ['temp'],
Flags=win32con.OFN_ALLOWMULTISELECT|win32con.OFN_EXPLORER,
File='somefilename', DefExt='py',
Title='GetOpenFileNameW',
Filter=filter,
CustomFilter=customfilter,
FilterIndex=0)
print 'open file names:', repr(fname)
print 'filter used:', repr(customfilter)
print 'Flags:', flags
for k,v in win32con.__dict__.items():
if k.startswith('OFN_') and flags & v:
print '\t'+k
Using tkinter (python 2) or Tkinter (python 3) it's indeed possible to display file open dialog (See other answers here). Please notice however that user interface of that dialog is outdated and does not corresponds to newer file open dialogs available in Windows 10.
Moreover - if you're looking on way to embedd python support into your own application - you will find out soon that tkinter library is not open source code and even more - it is commercial library.
(For example search for "activetcl pricing" will lead you to this web page: https://reviews.financesonline.com/p/activetcl/)
So tkinter library will cost money for any application wanting to embedd python.
I by myself managed to find pythonnet library:
Overview here: http://pythonnet.github.io/
Source code here: https://github.com/pythonnet/pythonnet
(MIT License)
Using following command it's possible to install pythonnet:
pip3 install pythonnet
And here you can find out working example for using open file dialog:
https://stackoverflow.com/a/50446803/2338477
Let me copy an example also here:
import sys
import ctypes
co_initialize = ctypes.windll.ole32.CoInitialize
# Force STA mode
co_initialize(None)
import clr
clr.AddReference('System.Windows.Forms')
from System.Windows.Forms import OpenFileDialog
file_dialog = OpenFileDialog()
ret = file_dialog.ShowDialog()
if ret != 1:
print("Cancelled")
sys.exit()
print(file_dialog.FileName)
If you also miss more complex user interface - see Demo folder
in pythonnet git.
I'm not sure about portability to other OS's, haven't tried, but .net 5 is planned to be ported to multiple OS's (Search ".net 5 platforms", https://devblogs.microsoft.com/dotnet/introducing-net-5/ ) - so this technology is also future proof.
If you don't need the UI or expect the program to run in a CLI, you could parse the filepath as an argument. This would allow you to use the autocomplete feature of your CLI to quickly find the file you need.
This would probably only be handy if the script is non-interactive besides the filepath input.
Another os-agnostic option, use pywebview:
import webview
def webview_file_dialog():
file = None
def open_file_dialog(w):
nonlocal file
try:
file = w.create_file_dialog(webview.OPEN_DIALOG)[0]
except TypeError:
pass # user exited file dialog without picking
finally:
w.destroy()
window = webview.create_window("", hidden=True)
webview.start(open_file_dialog, window)
# file will either be a string or None
return file
print(webview_file_dialog())
Environment: python3.8.6 on Mac - though I've used pywebview on windows 10 before.
I just stumbled on this little trick for Windows only: run powershell.exe from subprocess.
import subprocess
sys_const = ssfDESKTOP # Starts at the top level
# sys_const = 0x2a # Correct value for "Program Files (0x86)" folder
powershell_browse = "(new-object -COM 'Shell.Application')."
powershell_browse += "BrowseForFolder(0,'window title here',0,sys_const).self.path"
ret = subprocess.run(["powershell.exe",powershell_browse], stdout=subprocess.PIPE)
print(ret.stdout.decode())
Note the optional use of system folder constants. (There's an obscure typo in shldisp.h that the "Program Files (0x86)" constant was assigned wrong. I added a comment with the correct value. Took me a bit to figure that one out.)
More info below:
System folder constants

Dialog box unresponsive with Windows Script Host (Python)

I am trying to modify the Print Setup option found under File > Print Setup.
I am using Windows Script Host with Python. I use the Alt + F followed by S to open the appropriate dialogue box:
When I do those commands by hand, the Print Setup box is in focus, so I can press F to select "Print to File" then {ENTER} or O to accept the changes.
However, I neither ALT+F nor F is selecting the File option.
shell = win32com.client.Dispatch("WScript.Shell")
shell.AppActivate('Point of Sale')
shell.SendKeys("%fs") # I also tried "%fsf and "%fs%f" removing the other call to SendKeys"
time.sleep(0.1) # Removing this (or using a longer wait) makes no difference
shell.SendKeys("F")
You have to wait for the dialog to appear before sending "F".
Try this:
shell.SendKeys("%fs")
time.sleep(.25)
shell.SendKeys("f")
This problem had to do with incorrect implementing on part of the developer of this software. To solve the problem, I used SendKeys to send multiple TABS until File was selected.

Have Win32 MessageBox appear over other programs

I've recently started learning Python and wrote a little script that informs me when a certain website changes content. I then added it as a scheduled task to Windows so it can run every 10 minutes. I'd like to be informed of the website changing right away so I added a win32ui MessageBox that pops up if the script detects that the website has changed. Here's the little code snippet I'm using for the MessageBox (imaginative text, I know):
win32ui.MessageBox("The website has changed.", "Website Change", 0)
My issue is this, I spend most of my time using remote desktop so when the MessageBox does pop up it sits behind the remote desktop session, is there any way to force the MessageBox to appear on top of it?
On a similar note when the script runs the command line opens up very briefly over the remote desktop session which I don't want, is there any way of stopping this behaviour?
I'm happy with Windows specific solutions as I'm aware it might mean dealing with the windowing manager or possibly an alternative way to inform me rather than using a MessageBox.
When you start anything from Task Scheduler, Windows blocks any "easy" ways to bring your windows or dialogs to top.
First way - use MB_SYSTEMMODAL (4096 value) flag. In my experience, it makes Msg dialog "Always on top".
win32ui.MessageBox("The website has changed.", "Website Change", MB_SYSTEMMODAL)
Second way - try to bring your console/window/dialog to the front with Following calls. Of course, if you use MessageBox you must do that (for your own created window) before calling MessageBox.
SetForegroundWindow(Wnd);
BringWindowToTop(Wnd);
SetForegroundWindow(Wnd);
As for flickering of the console window, you may try to start Python in a hidden state. For example, use ConEmu, ‘HidCon’ or cmdow. Refer to their parameters, something like:
ConEmu -basic -MinTSA -cmd C:\Python27\python.exe C:\pythonScript.py
or
CMDOW /RUN /MIN C:\Python27\python.exe C:\pythonScript.py
Avoiding the command window flash is done by naming the script with a pyw extension instead of simply py. You might also use pythonw.exe instead of python.exe, it really depends on your requirements.
See http://onlamp.com/pub/a/python/excerpts/chpt20/index.html?page=2
Use ctypes it displays an windows error message box very easy to use,
import ctypes
if condition:
ctypes.windll.user32.MessageBoxW(0, u"Error", u"Error", 0)
This works for me:
from ctypes import *
def MessageBox(title, text, style):
sty = int(style) + 4096
return windll.user32.MessageBoxW(0, text, title, sty) #MB_SYSTEMMODAL==4096
## Button Styles:
### 0:OK -- 1:OK|Cancel -- 2:Abort|Retry|Ignore -- 3:Yes|No|Cancel -- 4:Yes|No -- 5:Retry|No -- 6:Cancel|Try Again|Continue
## To also change icon, add these values to previous number
### 16 Stop-sign ### 32 Question-mark ### 48 Exclamation-point ### 64 Information-sign ('i' in a circle)
Usage:
MessageBox('Here is my Title', 'Message to be displayed', 64)
Making the message box system modal will cause it to pop up over every application, but none can be interacted with until it is dismissed. Consider either creating a custom dialog box window that you can bring to the front or using a notification bubble instead.
Windows tries to make it hard to pop a window over the active application. Users find it annoying, especially since the interrupting window generally steals keyboard focus.
The Windows way to give a notification like this is with a balloon in the notification area rather than a message box. Notification balloons don't steal focus and are (supposedly) less distracting.
I'm not sure if the python Windows UI library offers wrappers for notification balloons.
Very easy modal async message box with help of Python and MSG command (working on Win10):
# In CMD (you may use Username logged on target machine instead of * to send message to particular user):
msg /server:IP_or_ComputerName * /v /time:appearance_in_secs Message_up_to_255_chars
# I.e. send "Hello everybody!" to all users on 192.168.0.110 disappearing after 5 mins
msg /server:192.168.0.110 * /v /time:300 "Hello everybody!"
In Python I've been using subprocess to send CMD commands, allows me to read and process output, find error etc.
import subprocess as sp
name = 'Lucas'
message = f'Express yourself {name} in 255 characters ;)'
command = f'msg /server:192.168.0.110 * /v /time:360 "{message}"'
output = str(sp.run(command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT))
if 'returncode=0' in output:
pint('Message sent')
else:
print('Error occurred. Details:\n')
print(output[output.index('stdout=b'):])

Categories

Resources