From 0c1bfa3620cf68e3d49b46fe2d27f74ddf94ce10 Mon Sep 17 00:00:00 2001 From: gryf Date: Fri, 23 Dec 2016 19:22:37 +0100 Subject: [PATCH] Added ability to show and destroy message windows --- fs_uae_wrapper/message.py | 62 +++++++++++++++++++++++++++++++++++ tests/test_message.py | 68 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 130 insertions(+) create mode 100644 fs_uae_wrapper/message.py create mode 100644 tests/test_message.py diff --git a/fs_uae_wrapper/message.py b/fs_uae_wrapper/message.py new file mode 100644 index 0000000..eb5066c --- /dev/null +++ b/fs_uae_wrapper/message.py @@ -0,0 +1,62 @@ +""" +Display message in separate process +""" +import multiprocessing as mp +import sys +try: + import tkinter as tk + from tkinter import ttk +except ImportError: + import Tkinter as tk + import ttk + + +class MessageGui(tk.Tk): + """Simple gui for displaying a message""" + + def __init__(self, parent=None, msg=""): + tk.Tk.__init__(self, parent) + + self.grid() + self.resizable(False, False) + + self.parent = parent + # Display window without decorations + self.wm_attributes('-type', 'splash') + + self.frame = ttk.Frame(self, padding=5, borderwidth=0) + self.frame.grid() + ttk.Label(self.frame, text=msg, relief="ridge", padding=10).grid() + + if 'linux' in sys.platform: + style = ttk.Style() + style.theme_use('clam') + + def __call__(self): + self.mainloop() + + +class Message(object): + """Simple class for displaying a GUI message""" + + def __init__(self, msg): + self.msg = msg + self._process = None + + def show(self): + """Spawn new process with tkinter window with a message""" + + self._process = mp.Process(target=_spawn, args=(self.msg, )) + self._process.start() + + def close(self): + """Terminate the process with gui""" + if self._process.is_alive(): + self._process.terminate() + self._process.join() + + +def _spawn(msg): + """Spawn gui for displaying message""" + app = MessageGui(msg=msg) + app() diff --git a/tests/test_message.py b/tests/test_message.py new file mode 100644 index 0000000..ea6c910 --- /dev/null +++ b/tests/test_message.py @@ -0,0 +1,68 @@ +from unittest import TestCase +try: + import tkinter as tk + from tkinter import ttk +except ImportError: + import Tkinter as tk + import ttk + +try: + from unittest import mock +except ImportError: + import mock + +from fs_uae_wrapper import message + + +class TestMessage(TestCase): + + @mock.patch('multiprocessing.Process.start') + def test_show(self, process_start): + msg = message.Message('display that') + msg.show() + process_start.assert_called_once() + + def test_close(self): + msg = message.Message('display that') + msg._process = mock.MagicMock() + msg._process.is_alive = mock.MagicMock(return_value=True) + msg._process.terminate = mock.MagicMock() + msg._process.join = mock.MagicMock() + + msg.close() + msg._process.is_alive.assert_called_once() + msg._process.terminate.assert_called_once() + msg._process.join.assert_called_once() + + msg._process.is_alive = mock.MagicMock(return_value=False) + msg._process.terminate.reset_mock() + msg._process.join.reset_mock() + + msg.close() + msg._process.is_alive.assert_called_once() + msg._process.terminate.assert_not_called() + msg._process.join.assert_called_once() + + +class TestSpawn(TestCase): + + @mock.patch('fs_uae_wrapper.message.MessageGui.__call__') + def test_spawn(self, call): + self.assertIsNone(message._spawn('')) + call.assert_called_once() + + +class TestMessageGui(TestCase): + + def test_gui(self): + msg = message.MessageGui(msg='display that') + self.assertIsInstance(msg, tk.Tk) + self.assertIsInstance(msg.frame, ttk.Frame) + label = next(iter(msg.frame.children.values())) + self.assertEqual(label.cget('text'), 'display that') + + @mock.patch('fs_uae_wrapper.message.tk.Tk.mainloop') + def test_call(self, tkmain): + msg = message.MessageGui(msg='display that') + msg() + tkmain.assert_called_once()