Commit 775d39b8 authored by Michael Rudolf's avatar Michael Rudolf
Browse files

GUI Update

- Simplified checkboxes
- Added icons
- Switched to ttk widgets
- Some widgets respond to selections
resolves #9
parent a17373d6
...@@ -69,14 +69,20 @@ For a more detailed description of the other components see the ...@@ -69,14 +69,20 @@ For a more detailed description of the other components see the
[Documentation](https://gitext.gfz-potsdam.de/analab-code/rst-evaluation/blob/master/Documentation/) [Documentation](https://gitext.gfz-potsdam.de/analab-code/rst-evaluation/blob/master/Documentation/)
and the readme files in the individual folders. and the readme files in the individual folders.
## Acknowledgements ## Acknowledgements
The original scripts for version 0.0.1 (4260ec45) in this repository have been provided by M. Warsitzka @warsitzka_at_ig.cas.cz and contain scripts that have been developed by M. Ritter. The original scripts for version 0.0.1 (4260ec45) in this repository have been provided by M. Warsitzka @warsitzka_at_ig.cas.cz and contain scripts that have been developed by M. Ritter.
Warsitzka, Michael; Ge, Zhiyuan; Schönebeck, Jan-Michael; Pohlenz, Andre; Kukowski, Nina (2019): Ring-shear test data of foam glass beads used for analogue experiments in the Helmholtz Laboratory for Tectonic Modelling (HelTec) at the GFZ German Research Centre for Geosciences in Potsdam and the Institute of Geosciences, Friedrich Schiller University Jena. GFZ Data Services. http://doi.org/10.5880/GFZ.4.1.2019.002 Warsitzka, Michael; Ge, Zhiyuan; Schönebeck, Jan-Michael; Pohlenz, Andre; Kukowski, Nina (2019): Ring-shear test data of foam glass beads used for analogue experiments in the Helmholtz Laboratory for Tectonic Modelling (HelTec) at the GFZ German Research Centre for Geosciences in Potsdam and the Institute of Geosciences, Friedrich Schiller University Jena. GFZ Data Services. http://doi.org/10.5880/GFZ.4.1.2019.002
This software reuses images for the user interface that are part of matplotlib (Hunter, 2007).
## Citation ## Citation
Please cite this repository as: Please cite this repository as:
Rudolf, Michael; Warsitzka, Michael (2021): RST Evaluation - Scripts for analysing shear experiments from the Schulze RST.pc01 ring shear tester. GFZ Data Services. https://doi.org/10.5880/GFZ.4.1.2021.001 Rudolf, Michael; Warsitzka, Michael (2021): RST Evaluation - Scripts for analysing shear experiments from the Schulze RST.pc01 ring shear tester. GFZ Data Services. https://doi.org/10.5880/GFZ.4.1.2021.001
## References
[J. D. Hunter, "Matplotlib: A 2D Graphics Environment", Computing in Science & Engineering, vol. 9, no. 3, pp. 90-95, 2007.](https://doi.org/10.1109/MCSE.2007.55)
\ No newline at end of file
...@@ -12,25 +12,14 @@ GUI based approach for RSTpicking ...@@ -12,25 +12,14 @@ GUI based approach for RSTpicking
""" """
import os
import tkinter as tk
import matplotlib as mpl import matplotlib as mpl
from rstevaluation import mainGUI, utilities from rstevaluation import mainGUI
def run(): def run():
app = mainGUI.RST_pick_GUI(None) app = mainGUI.RST_pick_GUI(None)
app.title('RSTpick GUI') app.title('RSTpick GUI')
image_path = utilities.resource_path(
os.path.join('images', 'rst-evaluation_x256.ico')
)
try:
app.iconbitmap(image_path)
except tk.TclError:
pass
mpl.use('qt5agg') mpl.use('qt5agg')
app.mainloop() app.mainloop()
......
""" Contains some custom classes for the use with the main GUI """
import tkinter as tk
from tkinter import ttk
class ToolTip(object):
"""
ToolTip object which is shown while hovering over an element.
Adapted from:
https://stackoverflow.com/questions/20399243/display-message-when-hovering-over-something-with-mouse-cursor-in-python
Possibly contains code by voidspace.org.uk (offline at the time of writing)
"""
def __init__(self, widget):
self.widget = widget
self.tipwindow = None
self.id = None
self.x = self.y = 0
def showtip(self, text):
"Display text in tooltip window"
self.text = text
if self.tipwindow or not self.text:
return
x, y, cx, cy = self.widget.bbox("insert")
x = x + self.widget.winfo_rootx() + 57
y = y + cy + self.widget.winfo_rooty() + 27
self.tipwindow = tw = tk.Toplevel(self.widget)
tw.wm_overrideredirect(1)
tw.wm_geometry("+%d+%d" % (x, y))
label = ttk.Label(
tw,
text=self.text, justify=tk.LEFT,
background="#ffffe0", relief=tk.SOLID, borderwidth=1,
font=("tahoma", "8", "normal")
)
label.pack(ipadx=1)
def hidetip(self):
tw = self.tipwindow
self.tipwindow = None
if tw:
tw.destroy()
def CreateToolTip(widget, text):
toolTip = ToolTip(widget)
def enter(event):
toolTip.showtip(text)
def leave(event):
toolTip.hidetip()
widget.bind('<Enter>', enter)
widget.bind('<Leave>', leave)
...@@ -14,7 +14,7 @@ import numpy as np ...@@ -14,7 +14,7 @@ import numpy as np
import uncertainties as unc import uncertainties as unc
from tqdm import tqdm from tqdm import tqdm
from . import data as rstdat from rstevaluation import data as rstdat
def convert(path, file_in, config): def convert(path, file_in, config):
......
""" Provides PhotoImage objects for all images """
import os
import tkinter as tk
from importlib import resources
def icon_rst():
""" Returns main application icon """
with resources.path('rstevaluation.icons', 'rst-evaluation.png') as fpath:
phim = tk.PhotoImage(
file=fpath
)
return phim
def icon_load():
""" Returns an icon for loading from a folder """
with resources.path('rstevaluation.icons', 'home.png') as fpath:
phim = tk.PhotoImage(
file=fpath
)
return phim
def icon_save():
""" Returns an icon for saving to a folder """
with resources.path('rstevaluation.icons', 'filesave.png') as fpath:
phim = tk.PhotoImage(
file=fpath
)
return phim
def icon_options():
""" Returns an icon for options """
with resources.path('rstevaluation.icons', 'subplots.png') as fpath:
phim = tk.PhotoImage(
file=fpath
)
return phim
def icon_start():
""" Returns an icon for processing """
with resources.path(
'rstevaluation.icons', 'qt4_editor_options.png'
) as fpath:
phim = tk.PhotoImage(
file=fpath
)
return phim
...@@ -6,9 +6,12 @@ import pathlib ...@@ -6,9 +6,12 @@ import pathlib
import re import re
import sys import sys
import tkinter as tk import tkinter as tk
from tkinter import filedialog, messagebox from tkinter import filedialog, messagebox, ttk
from . import processing as rstprocess import rstevaluation
from rstevaluation import RST_pick_GUI as main
from rstevaluation import get_icons as rsticons
from rstevaluation import processing as rstprocess
class RST_pick_GUI(tk.Tk): class RST_pick_GUI(tk.Tk):
...@@ -26,9 +29,9 @@ class RST_pick_GUI(tk.Tk): ...@@ -26,9 +29,9 @@ class RST_pick_GUI(tk.Tk):
self.plot_ts = tk.IntVar() self.plot_ts = tk.IntVar()
self.save_ts = tk.IntVar() self.save_ts = tk.IntVar()
self.rev_pick = tk.IntVar() self.rev_pick = tk.IntVar()
self.is_VST = tk.IntVar()
self.pred_norm = tk.IntVar() self.pred_norm = tk.IntVar()
self.rst = tk.IntVar() self.stick_slip = tk.IntVar()
self.is_rst = tk.IntVar()
self.cfg = configparser.ConfigParser() self.cfg = configparser.ConfigParser()
self.cfg.optionxform = str self.cfg.optionxform = str
self.path_cfg.set('rst_evaluation_') self.path_cfg.set('rst_evaluation_')
...@@ -46,122 +49,175 @@ class RST_pick_GUI(tk.Tk): ...@@ -46,122 +49,175 @@ class RST_pick_GUI(tk.Tk):
self.grid() self.grid()
# Project name # Project name
self.label_projname = tk.Label( self.label_projname = ttk.Label(
self, self,
text='Project:', text='Project:',
anchor='e',
width=20 width=20
) )
self.label_projname.grid(column=0, row=0, sticky='EW') self.label_projname.grid(column=0, row=0, sticky='EW')
self.entry_projname = tk.Entry( self.entry_projname = ttk.Entry(
self, self,
textvariable=self.projectname) textvariable=self.projectname)
self.entry_projname.grid(column=1, row=0, sticky='EW') self.entry_projname.grid(column=1, row=0, sticky='EW')
# Input path # Input path
self.label_input = tk.Label( self.label_input = ttk.Label(
self, self,
text='Input Folder:', text='Input Folder:',
anchor='e') )
self.label_input.grid(column=0, row=1, sticky='EW') self.label_input.grid(column=0, row=1, sticky='EW')
self.entry_input = tk.Entry( self.entry_input = ttk.Entry(
self, self,
width=80, width=80,
textvariable=self.path_in) textvariable=self.path_in)
self.entry_input.grid(column=1, row=1, sticky='EW') self.entry_input.grid(column=1, row=1, sticky='EW')
self.button_input = tk.Button( icon = rsticons.icon_load()
self.button_input = ttk.Button(
self, self,
text='...') image=icon
)
self.button_input.image = icon
self.button_input.grid(column=2, row=1) self.button_input.grid(column=2, row=1)
self.button_input.bind('<ButtonRelease-1>', self.folder_browser) self.button_input.bind('<ButtonRelease-1>', self.folder_browser)
# Output path # Output path
self.label_output = tk.Label( self.label_output = ttk.Label(
self, self,
text='Output Folder:', text='Output Folder:',
anchor='e') )
self.label_output.grid(column=0, row=2, sticky='EW') self.label_output.grid(column=0, row=2, sticky='EW')
self.entry_output = tk.Entry( self.entry_output = ttk.Entry(
self, self,
textvariable=self.path_out) textvariable=self.path_out)
self.entry_output.grid(column=1, row=2, sticky='EW') self.entry_output.grid(column=1, row=2, sticky='EW')
self.button_output = tk.Button( icon = rsticons.icon_save()
self.button_output = ttk.Button(
self, self,
text='...') image=icon
)
self.button_output.icon = icon
self.button_output.grid(column=2, row=2) self.button_output.grid(column=2, row=2)
self.button_output.bind('<ButtonRelease-1>', self.folder_browser) self.button_output.bind('<ButtonRelease-1>', self.folder_browser)
# Options # Options
self.label_options = tk.Label( self.label_options = ttk.Label(
self, self,
text='Options:', text='Options:',
anchor='w', font=('Helvetica', 12, 'bold')
font=('Helvetica', 12, 'bold')) )
self.label_options.grid(column=0, row=3, columnspan=3, sticky='EW') self.label_options.grid(column=0, row=3, columnspan=3, sticky='EW')
# Pick Data # Is a RST-Test
self.opt_pick = tk.Checkbutton( self.opt_rst = ttk.Checkbutton(
self,
text='Automatic Picking',
anchor='w',
variable=self.rst)
self.opt_pick.grid(column=0, row=4, sticky='EW')
# Save Data
self.opt_save = tk.Checkbutton(
self, self,
text='Save Data', text='RST Test',
anchor='w', variable=self.is_rst
variable=self.save_ts) )
self.opt_save.grid(column=0, row=5, sticky='EW') self.opt_rst.grid(column=0, row=4, sticky='EW')
self.opt_rst.bind('<ButtonRelease-1>', self.switch_pred_load)
# Plot Data
self.opt_plot = tk.Checkbutton(
self,
text='Plot time series',
anchor='w',
variable=self.plot_ts)
self.opt_plot.grid(column=0, row=6, sticky='EW')
# Review Picking
self.opt_revpick = tk.Checkbutton(
self,
text='Review picking during run',
anchor='w',
variable=self.rev_pick)
self.opt_revpick.grid(column=1, row=4, sticky='EW')
# Use predefined normal stress # Use predefined normal stress
self.opt_pred = tk.Checkbutton( self.opt_pred = ttk.Checkbutton(
self, self,
text='Use predefined normal stress', text='Use predefined normal stress',
anchor='w',
variable=self.pred_norm) variable=self.pred_norm)
self.opt_pred.grid(column=1, row=5, sticky='EW') self.opt_pred.grid(column=0, row=5, sticky='EW')
# Is a VST-Test # Is a VST-Test
self.opt_revpick = tk.Checkbutton( self.opt_vst = ttk.Checkbutton(
self,
text='VST Test',
variable=self.is_rst,
offvalue=1,
onvalue=0
)
self.opt_vst.grid(column=1, row=4, sticky='EW')
self.opt_vst.bind('<ButtonRelease-1>', self.switch_pred_load)
# Stick-Slip Detection
self.opt_stickslip = ttk.Checkbutton(
self, self,
text='VST-Test', text='Stick-Slip Detection',
anchor='w', variable=self.stick_slip)
variable=self.is_VST) self.opt_stickslip.grid(column=1, row=5, sticky='EW')
self.opt_revpick.grid(column=1, row=6, sticky='EW')
# More Options # More Options
self.button_options = tk.Button( icon = rsticons.icon_options()
self.button_options = ttk.Button(
self, self,
text='More options...') text='More options',
self.button_options.grid(column=1, row=7, sticky='w') image=icon,
compound=tk.LEFT
)
self.button_options.icon = icon
self.button_options.grid(column=0, row=7, sticky='w')
self.button_options.bind('<ButtonRelease-1>', self.more_options) self.button_options.bind('<ButtonRelease-1>', self.more_options)
# Start processing # Start processing
self.button_start = tk.Button( icon = rsticons.icon_start()
self.button_start = ttk.Button(
self, self,
text='Start Processing', text='Start Processing',
padx=20) image=icon,
self.button_start.grid(column=0, row=7, columnspan=3, sticky='w') compound=tk.LEFT
)
self.button_start.icon = icon
self.button_start.grid(column=1, row=7, sticky='e')
self.button_start.bind('<ButtonRelease-1>', self.start_processing) self.button_start.bind('<ButtonRelease-1>', self.start_processing)
self.iconphoto(True, rsticons.icon_rst())
self.make_dpi_aware()
self.update()
def get_HWND_dpi(self):
"""Detects high dpi displays and rescales gui in Windows
Adapted from the user 'dingles at stack-overflow"""
if os.name == "nt":
from ctypes import pointer, windll, wintypes
try:
windll.shcore.SetProcessDpiAwareness(1)
except Exception:
print('High-DPI scaling failed')
pass # this will fail on Win Server and maybe early Windows
DPI100pc = 96 # DPI 96 is 100% scaling
DPI_type = 0
# MDT_EFFECTIVE_DPI = 0, MDT_ANGULAR_DPI = 1, MDT_RAW_DPI = 2
winH = wintypes.HWND(self.winfo_id())
monitorhandle = windll.user32.MonitorFromWindow(winH,
wintypes.DWORD(2))
# MONITOR_DEFAULTTONEAREST = 2
X = wintypes.UINT()
Y = wintypes.UINT()
try:
windll.shcore.GetDpiForMonitor(monitorhandle,
DPI_type,
pointer(X),
pointer(Y))
return X.value, Y.value, (X.value + Y.value) / (2 * DPI100pc)
except Exception:
print('Assuming standard dpi scaling.')
return 96, 96, 1 # Assume standard Windows DPI & scaling
else:
return None, None, 1 # What to do for other OSs?
def make_dpi_aware(self):
"""Adapted from the user 'dingles at stack-overflow"""
def TkGeometryScale(s, cvtfunc):
# format "WxH+X+Y"
patt = r"(?P<W>\d+)x(?P<H>\d+)\+(?P<X>\d+)\+(?P<Y>\d+)"
R = re.compile(patt).search(s)
G = str(cvtfunc(R.group("W"))) + "x"
G += str(cvtfunc(R.group("H"))) + "+"
G += str(cvtfunc(R.group("X"))) + "+"
G += str(cvtfunc(R.group("Y")))
return G
self.DPI_X, self.DPI_Y, self.DPI_scaling = self.get_HWND_dpi()
self.TkScale = lambda v: int(float(v) * self.DPI_scaling)
self.TkGeometryScale = lambda s: TkGeometryScale(s, self.TkScale)
def plot_window(self, event): def plot_window(self, event):
"""Shows a plot window""" """Shows a plot window"""
plot_win = tk.Toplevel(self) plot_win = tk.Toplevel(self)
...@@ -198,28 +254,39 @@ class RST_pick_GUI(tk.Tk): ...@@ -198,28 +254,39 @@ class RST_pick_GUI(tk.Tk):
if messagebox.askyesno('Close Program', 'Quit?'): if messagebox.askyesno('Close Program', 'Quit?'):
sys.exit(0) sys.exit(0)
def switch_pred_load(self, event):
""" Switches the predefined normal load to inactive for VST """
try:
if self.is_rst.get():
self.opt_pred['state'] = tk.DISABLED
else:
self.opt_pred['state'] = tk.NORMAL
except AttributeError as _:
pass
# == CONFIG STUFF ==
def more_options(self, event): def more_options(self, event):
"""Shows all additional options for the processing""" """Shows all additional options for the processing"""
opt_dlg = tk.Toplevel(self) opt_dlg = tk.Toplevel(self)
opt_dlg.wm_title('More Options') opt_dlg.wm_title('More Options')
opt_dlg.grid() opt_dlg.grid()
opt_dlg.label_options = tk.Label( opt_dlg.label_options = ttk.Label(
opt_dlg, opt_dlg,
text='Options:') text='Options:')
opt_dlg.label_options.grid(column=0, row=0, sticky='EW') opt_dlg.label_options.grid(column=0, row=0, sticky='EW')
# Dynamically generate options based on config entries # Dynamically generate options based on config entries
for (i, item) in enumerate(self.cfg['parameters'].items()): for (i, item) in enumerate(self.cfg['parameters'].items()):
opt_dlg.label_item = tk.Label( opt_dlg.label_item = ttk.Label(
opt_dlg, opt_dlg,
text=item[0] + ':') text=item[0] + ':')
opt_dlg.label_item.grid(column=0, row=i + 1, sticky='e') opt_dlg.label_item.grid(column=0, row=i + 1, sticky='e')
opt_dlg.entry_item = tk.Entry( opt_dlg.entry_item = ttk.Entry(
opt_dlg, opt_dlg,
textvariable=self.params[item[0]], textvariable=self.params[item[0]],
justify='right', justify='right',
width=45) width=45)
opt_dlg.entry_item.grid(column=1, row=i + 1, sticky='EW') opt_dlg.entry_item.grid(column=1, row=i + 1, sticky='EW')
opt_dlg.label_unit = tk.Label( opt_dlg.label_unit = ttk.Label(
opt_dlg, opt_dlg,
text=self.cfg['units'][item[0]]) text=self.cfg['units'][item[0]])
opt_dlg.label_unit.grid(column=2, row=i + 1, sticky='w') opt_dlg.label_unit.grid(column=2, row=i + 1, sticky='w')
...@@ -233,9 +300,8 @@ class RST_pick_GUI(tk.Tk): ...@@ -233,9 +300,8 @@ class RST_pick_GUI(tk.Tk):