Skip to content

Instantly share code, notes, and snippets.

@tbnorth
Last active August 8, 2020 11:45
Show Gist options
  • Save tbnorth/9f4f61c0c3af269b9eae598170c3c00b to your computer and use it in GitHub Desktop.
Save tbnorth/9f4f61c0c3af269b9eae598170c3c00b to your computer and use it in GitHub Desktop.
A PyQt "task launcher" for quick access to python scripts.
"""
A PyQt piece of black tape to cover annoying screen features.
terrynbrown@gmail.com, 2019-10-03
"""
import sys
try:
from PyQt5 import QtWidgets, QtCore, Qt
from PyQt5.QtCore import Qt as QtConst
QtGui = QtWidgets
except ImportError:
from PyQt4 import QtGui, QtCore, Qt
from PyQt4.QtCore import Qt as QtConst
class Draggable(QtGui.QWidget):
"""
A draggable widget, so the window can be moved by dragging
its background. Thanks http://stackoverflow.com/a/7140226/1072212
"""
def __init__(self, *args, **kwargs):
"""__init__"""
QtGui.QWidget.__init__(self, *args, **kwargs)
# self.setMouseTracking(True)
self.offset = None
self.msg_i = 0
self.orig_size = None
self.setLayout(QtGui.QVBoxLayout())
self.top_row = QtGui.QHBoxLayout()
self.layout().addLayout(self.top_row)
self.bot_row = QtGui.QHBoxLayout()
self.layout().addLayout(self.bot_row)
self.bot_row.addItem(QtGui.QSpacerItem(15, 5))
for layout in self.bot_row, self.top_row, self.layout():
layout.setSpacing(0)
layout.setContentsMargins(0, 0, 0, 0)
def mousePressEvent(self, event):
self.offset = event.pos()
def mouseMoveEvent(self, event):
x=event.globalX()
y=event.globalY()
x_w = self.offset.x()
y_w = self.offset.y()
self.parent().move(x-x_w, y-y_w)
holder = []
def new_widget():
main = QtGui.QMainWindow(None,
# QtConst.CustomizeWindowHint |
QtConst.WindowStaysOnTopHint |
QtConst.FramelessWindowHint # |
# QtConst.WindowCloseButtonHint
)
mainwidj = Draggable()
def resize(w=main):
w.setStyleSheet("background: black")
w.resize(int(sys.argv[1]), int(sys.argv[2]))
w.timer.stop()
main.timer = timer = QtCore.QTimer()
timer.setInterval(10000)
timer.timeout.connect(resize)
timer.start()
main.setCentralWidget(mainwidj)
main.show()
return main
def main():
app = Qt.QApplication(sys.argv)
holder[:] = [new_widget()]
app.exec_()
if __name__ == '__main__':
main()
"""
A PyQt "task launcher" for quick access to python scripts.
Buttons to click to make working in Windows less unproductive.
e.g. a button to move the current window to top or bottom half
of screen, because Windows-Up / Windows-Down doesn't do that.
Or quote the text on the clipboard properly, because Outlook
can't do that.
terrynbrown@gmail.com, 2016-12-23
"""
import os
import sys
import time
try:
from PyQt5 import QtWidgets, QtCore, Qt
from PyQt5.QtCore import Qt as QtConst
QtGui = QtWidgets
except ImportError:
from PyQt4 import QtGui, QtCore, Qt
from PyQt4.QtCore import Qt as QtConst
COMMANDS = []
MSG_FILES = ["~/.winbut_todo_int", "~/.winbut_todo_ext"]
ON_TIME = 300
HI_TIME = 30
def get_msgs():
msgs = []
for msg_file in MSG_FILES:
msg_file = os.path.expanduser(msg_file)
if os.path.exists(msg_file):
msgs.extend(open(msg_file).read().strip().split('\n'))
return [i for i in msgs if i.strip()]
class Draggable(QtGui.QWidget):
"""
A draggable widget, so the window can be moved by dragging
its background. Thanks http://stackoverflow.com/a/7140226/1072212
"""
def __init__(self, *args, **kwargs):
"""__init__"""
QtGui.QWidget.__init__(self, *args, **kwargs)
# self.setMouseTracking(True)
self.offset = None
self.msg_i = 0
self.orig_size = None
self.setLayout(QtGui.QVBoxLayout())
self.top_row = QtGui.QHBoxLayout()
self.layout().addLayout(self.top_row)
self.bot_row = QtGui.QHBoxLayout()
self.layout().addLayout(self.bot_row)
self.bot_row.addItem(QtGui.QSpacerItem(15, 5))
for layout in self.bot_row, self.top_row, self.layout():
layout.setSpacing(0)
layout.setContentsMargins(0, 0, 0, 0)
def mousePressEvent(self, event):
self.offset = event.pos()
def mouseMoveEvent(self, event):
x=event.globalX()
y=event.globalY()
x_w = self.offset.x()
y_w = self.offset.y()
self.parent().move(x-x_w, y-y_w)
def command(name):
"""Decorator to add a button to the task bar"""
def makebutton(function):
# can't make the button yet, no Qt app. Just add to list
COMMANDS.append((name, function))
return function
return makebutton
# now some commands to add to the bar, not part of the bar code itself
def place(x, y, w, h):
"""Wait up to 5 sec. for click on another window, then move
it to x, y, w, h.
"""
import win32con, win32gui, time
first = win32gui.GetForegroundWindow()
for i in range(100):
time.sleep(0.05)
hwnd = win32gui.GetForegroundWindow()
if hwnd != first:
win32gui.SetWindowPos(hwnd, win32con.HWND_TOP, x, y, w, h, 0)
break
@command("Upper")
def upper():
# place(-1050, -330, 1050, 809)
place(-1050+1050, -330+330, 1050, 809)
@command("Lower")
def lower():
# place(-1050, 479, 1050, 809)
place(-1050+1050, 479+330, 1050, 809)
@command("Quote")
def quote():
"""> Quote an email message, because Outlook can't.
Operates on the content of the clipboard.
"""
import re
clipboard = Qt.QApplication.clipboard()
text = "> " + unicode(clipboard.text()).replace("\n", "\n> ")
BLANKQUOTE = re.compile("^[> ]*$")
out = []
for line in text.split('\n'):
if BLANKQUOTE.match(line):
if out:
if BLANKQUOTE.match(out[-1]):
if len(out[-1]) > len(line):
out[-1] = line
else:
out.append(line)
else:
out.append(line)
# delete trailing blank quote lines
while out and BLANKQUOTE.match(out[-1]):
del out[-1]
# add trailing line
if out and out[-1].strip():
out.append('\n')
text = '\n'.join(out)
clipboard.setText(text)
@command("Note")
def note():
txt = str(QtGui.QInputDialog.getText(None, "Note", "Note")[0])
timestamp = time.strftime("%Y%m%d%H%M%S")
with open("d:/local/quick_notes/%s.txt" % timestamp, 'w') as out:
out.write("%s\n\n%s\n" % (txt, time.asctime()))
@command("ToDo")
def todo():
txt = str(QtGui.QInputDialog.getText(None, "To do", "To do")[0])
timestamp = time.strftime("%Y%m%d%H%M%S")
with open(os.path.expanduser(MSG_FILES[0]), 'a') as out:
out.write("%s %s\n" % (txt, timestamp))
# end of commands unrelated to bar code itself
@command("Exit")
def exit_():
exit()
def show_msgs():
w = holder[0].findChild(Draggable)
was_one = False
while True:
cull = w.top_row.takeAt(0)
if not cull:
break
was_one = True
cull.widget().deleteLater()
msgs = get_msgs()
if msgs:
w.msg_i = (w.msg_i+1) % len(msgs)
l = QtGui.QLabel(msgs[w.msg_i])
l.setStyleSheet("color: white; background: red")
w.top_row.addWidget(l)
QtCore.QTimer.singleShot(HI_TIME*1000,
lambda: l.setStyleSheet("color: black; background: white"))
else:
if was_one:
w.timer.stop()
holder[:] = [new_widget()]
holder = []
def new_widget():
main = QtGui.QMainWindow(None,
# QtConst.CustomizeWindowHint |
QtConst.WindowStaysOnTopHint |
QtConst.FramelessWindowHint # |
# QtConst.WindowCloseButtonHint
)
mainwidj = Draggable()
for name, function in COMMANDS:
button = QtGui.QPushButton(name)
button.clicked.connect(function)
# button.setSizePolicy(QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Minimum)
button.setMinimumWidth(40)
mainwidj.bot_row.addWidget(button)
mainwidj.timer = timer = QtCore.QTimer()
timer.setInterval(ON_TIME*1000)
timer.timeout.connect(show_msgs)
timer.start()
main.setCentralWidget(mainwidj)
main.show()
main.resize(min(800, 20+20*len(COMMANDS)),16)
x = Qt.QApplication.desktop().availableGeometry().bottomRight()
main.move(x - QtCore.QPoint(main.size().width(), main.size().height()))
return main
def main():
app = Qt.QApplication(sys.argv)
holder[:] = [new_widget()]
app.exec_()
if __name__ == '__main__':
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment