Skip to content

Commit a792031

Browse files
committed
Merged master into this branch
2 parents 3f7f41a + 32c9aaa commit a792031

File tree

12 files changed

+166
-31
lines changed

12 files changed

+166
-31
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ This section serves as an introduction for developers who are interested in main
2424
* [Data Matrix Reading](docs/datamatrix-reader.md)
2525
* [Unipuck Geometry Calculation](docs/unipuck.md)
2626
* [Camera Scanning](docs/scanning.md)
27+
* [Icons Tips](docs/icons_tips.md)
2728

2829
Release Notes
2930
-------------

build.bat

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ mkdir bin
33

44
cd dls_barcode
55

6-
pyinstaller --onefile --windowed main.py
6+
pyinstaller --onefile --windowed --icon=..\resources\icons\qr_code.ico --clean main.py
77

88
move dist\main.exe ..\bin\barcode.exe
99
rd /S /Q build

dls_barcode/data_store/store.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,6 @@ def _merge_holder_image_into_pins_image(self, holder_img, pins_img):
125125
merged_img.paste(small_holder_img, 0, 0)
126126
return merged_img
127127

128-
def is_new_holder_barcode(self, holder_barcode):
129-
known_holder_barcodes = [r.holder_barcode for r in self.records]
130-
return not holder_barcode in known_holder_barcodes
128+
def is_latest_holder_barcode(self, holder_barcode):
129+
latest_record = self.get_record(0)
130+
return latest_record is not None and holder_barcode == latest_record.holder_barcode

dls_barcode/gui/main_window.py

Lines changed: 40 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@ def __init__(self, config_file, version):
3232
# UI elements
3333
self._record_table = None
3434
self._barcode_table = None
35-
self.sideBarcodeWindow = None
3635
self._image_frame = None
3736

3837
# Scan elements
@@ -61,14 +60,16 @@ def __init__(self, config_file, version):
6160
self._message_timer.timeout.connect(self._read_message_queue)
6261
self._message_timer.start(MESSAGE_TIMER_PERIOD)
6362

64-
self._camera_switch.restart_live_capture_from_side()
63+
self._restart_live_capture_from_side()
6564

6665
def _init_ui(self):
6766
""" Create the basic elements of the user interface.
6867
"""
68+
self._init_icons()
69+
6970
self.setGeometry(100, 100, 1020, 650)
7071
self.setWindowTitle('Diamond Puck Barcode Scanner')
71-
self.setWindowIcon(QtGui.QIcon('web.png'))
72+
self.setWindowIcon(self._window_icon)
7273

7374
self.init_menu_bar()
7475

@@ -109,30 +110,37 @@ def _init_ui(self):
109110

110111
self.show()
111112

113+
def _init_icons(self):
114+
self._window_icon = QtGui.QIcon("..\\resources\\icons\\qr_code_32.png")
115+
self._start_capture_icon = self.style().standardIcon(QtGui.QStyle.SP_MediaPlay)
116+
self._exit_icon = self.style().standardIcon(QtGui.QStyle.SP_DialogCloseButton)
117+
self._config_icon = self.style().standardIcon(QtGui.QStyle.SP_FileDialogDetailedView)
118+
self._about_icon = self.style().standardIcon(QtGui.QStyle.SP_FileDialogInfoView)
119+
112120
def init_menu_bar(self):
113121
"""Create and populate the menu bar.
114122
"""
115123
# Continuous scanner mode
116-
live_action = QtGui.QAction(QtGui.QIcon('open.png'), '&Camera Capture', self)
124+
live_action = QtGui.QAction(self._start_capture_icon, '&Camera Capture', self)
117125
live_action.setShortcut('Ctrl+W')
118126
live_action.setStatusTip('Capture continuously from camera')
119127
live_action.triggered.connect(self._on_scan_action_clicked)
120128

121129
# Exit Application
122-
exit_action = QtGui.QAction(QtGui.QIcon('exit.png'), '&Exit', self)
130+
exit_action = QtGui.QAction(self._exit_icon, '&Exit', self)
123131
exit_action.setShortcut('Ctrl+Q')
124132
exit_action.setStatusTip('Exit application')
125133
exit_action.triggered.connect(self._cleanup)
126134
exit_action.triggered.connect(QtGui.qApp.quit)
127135

128136
# Open options dialog
129-
options_action = QtGui.QAction(QtGui.QIcon('exit.png'), '&Options', self)
137+
options_action = QtGui.QAction(self._config_icon, '&Config', self)
130138
options_action.setShortcut('Ctrl+O')
131139
options_action.setStatusTip('Open Options Dialog')
132140
options_action.triggered.connect(self._on_options_action_clicked)
133141

134142
# Show version number
135-
about_action = QtGui.QAction("About", self)
143+
about_action = QtGui.QAction(self._about_icon, "About", self)
136144
about_action.triggered.connect(self._on_about_action_clicked)
137145

138146
# Create menu bar
@@ -143,7 +151,7 @@ def init_menu_bar(self):
143151
scan_menu = menu_bar.addMenu('&Scan')
144152
scan_menu.addAction(live_action)
145153

146-
option_menu = menu_bar.addMenu('&Option')
154+
option_menu = menu_bar.addMenu('&Options')
147155
option_menu.addAction(options_action)
148156

149157
help_menu = menu_bar.addMenu('?')
@@ -157,7 +165,7 @@ def _on_scan_action_clicked(self):
157165
if not self._camera_capture_alive():
158166
self._initialise_scanner()
159167

160-
self._camera_switch.restart_live_capture_from_side()
168+
self._restart_live_capture_from_side()
161169

162170
def _on_options_action_clicked(self):
163171
result_ok = self._open_options_dialog()
@@ -166,10 +174,11 @@ def _on_options_action_clicked(self):
166174

167175
self._cleanup()
168176
self._initialise_scanner()
169-
self._camera_switch.restart_live_capture_from_side()
177+
self._restart_live_capture_from_side()
170178

171179
def _open_options_dialog(self):
172-
dialog = BarcodeConfigDialog(self._config, self._before_test_camera) # pass the object here and trigger when the button is pressed
180+
dialog = BarcodeConfigDialog(self._config, self._before_test_camera)
181+
dialog.setWindowIcon(self._config_icon)
173182
result_ok = dialog.exec_()
174183
return result_ok
175184

@@ -227,22 +236,23 @@ def _read_message_queue(self):
227236
# The result queue is read at a slower rate - use a timer to give it time to process a new barcode
228237
self._start_msg_timer()
229238
elif self._has_msg_timer_timeout():
230-
self._message_box.display(MessageFactory.duplicate_barcode_message())
239+
self._message_box.display(MessageFactory.latest_barcode_message())
231240
else:
232241
self._reset_msg_timer()
233242
self._message_box.display(MessageFactory.from_scanner_message(scanner_msg))
234243

235244
def _reset_msg_timer(self):
236-
self._duplicate_msg_timer = None
245+
self._duplicate_record_msg_timer = None
237246

238247
def _start_msg_timer(self):
239-
self._duplicate_msg_timer = time.time()
248+
self._duplicate_record_msg_timer = time.time()
240249

241250
def _msg_timer_is_running(self):
242-
return self._duplicate_msg_timer is not None
251+
return self._duplicate_record_msg_timer is not None
243252

244253
def _has_msg_timer_timeout(self):
245-
return self._msg_timer_is_running() and time.time() - self._duplicate_msg_timer > 2 * RESULT_TIMER_PERIOD / 1000
254+
timeout = 2 * RESULT_TIMER_PERIOD / 1000
255+
return self._msg_timer_is_running() and time.time() - self._duplicate_record_msg_timer > timeout
246256

247257
def _read_result_queue(self):
248258
""" Called every second; read any new results from the scan results queue, store them and display them.
@@ -268,33 +278,40 @@ def _read_side_scan(self):
268278
Beeper.beep()
269279
print("MAIN: puck barcode recorded")
270280
holder_barcode = plate.barcodes()[0]
271-
if self._record_table.is_new_holder_barcode (holder_barcode):
272-
self._current_holder_barcode = holder_barcode
281+
if not self._record_table.is_latest_holder_barcode(holder_barcode):
282+
self._latest_holder_barcode = holder_barcode
273283
self._latest_holder_image = holder_image
274284
self._message_box.display(MessageFactory.puck_recorded_message())
275-
self._camera_switch.restart_live_capture_from_top()
285+
self._restart_live_capture_from_top()
276286
else:
277-
self._message_box.display(MessageFactory.duplicate_barcode_message())
287+
self._message_box.display(MessageFactory.latest_barcode_message())
278288

279289
def _read_top_scan(self):
280290
if self._result_queue.empty():
281291
if self._camera_switch.is_top_scan_timeout():
282292
self._message_box.display(MessageFactory.scan_timeout_message())
283293
print("\n*** Scan timeout ***")
284-
self._camera_switch.restart_live_capture_from_side()
294+
self._restart_live_capture_from_side()
285295
return
286296

287297
# Get the result
288298
plate, pins_image = self._result_queue.get(False)
289299

290-
# Add new record to the table - side is the _current_holder_barcode read first, top is the plate
291-
self._record_table.add_record_frame(self._current_holder_barcode, plate, self._latest_holder_image, pins_image)
300+
# Add new record to the table - side is the _latest_holder_barcode read first, top is the plate
301+
self._record_table.add_record_frame(self._latest_holder_barcode, plate, self._latest_holder_image, pins_image)
292302
if not plate.is_full_valid():
293303
return
294304

295305
# Barcodes successfully read
296306
Beeper.beep()
297307
print("Scan Completed")
298308
self._message_box.display(MessageFactory.scan_completed_message())
309+
self._restart_live_capture_from_side()
310+
311+
def _restart_live_capture_from_top(self):
312+
self._camera_switch.restart_live_capture_from_top()
313+
314+
def _restart_live_capture_from_side(self):
315+
self._reset_msg_timer()
299316
self._camera_switch.restart_live_capture_from_side()
300317

dls_barcode/gui/message_factory.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33

44
class MessageFactory:
55
@staticmethod
6-
def duplicate_barcode_message():
7-
return Message(MessageType.WARNING, "Puck barcode already in database", lifetime=3)
6+
def latest_barcode_message():
7+
return Message(MessageType.WARNING, "Puck barcode already in latest record", lifetime=3)
88

99
@staticmethod
1010
def from_scanner_message(scanner_msg):

dls_barcode/gui/record_table.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ def _delete_selected_records(self):
137137
self._store.delete_records(records_to_delete)
138138
self._load_store_records()
139139

140-
def is_new_holder_barcode(self, holder_barcode):
141-
return self._store.is_new_holder_barcode(holder_barcode)
140+
def is_latest_holder_barcode(self, holder_barcode):
141+
return self._store.is_latest_holder_barcode(holder_barcode)
142142

143143

docs/icons_tips.md

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
Icons Tips
2+
==========
3+
4+
The icons used in the application are mostly standard system icons. They can be found under `QtGui.QStyle`, e.g. `QtGui.QStyle.SP_MediaPlay`.
5+
A list of icons is available [here](https://deptinfo-ensip.univ-poitiers.fr/ENS/pyside-docs/PySide/QtGui/QStyle.html?highlight=qstyle#PySide.QtGui.PySide.QtGui.QStyle.StandardPixmap).
6+
7+
To view them quickly, you can run the following code (taken from [here](https://joekuan.wordpress.com/2015/09/23/list-of-qt-icons/)):
8+
```
9+
import sys
10+
from PyQt4.QtCore import *
11+
from PyQt4.QtGui import *
12+
# from PyQt4.QtWidgets import *
13+
14+
15+
class Widget(QWidget):
16+
def __init__(self, parent=None):
17+
super(Widget, self).__init__()
18+
19+
icons = [
20+
'SP_ArrowBack',
21+
'SP_ArrowDown',
22+
'SP_ArrowForward',
23+
'SP_ArrowLeft',
24+
'SP_ArrowRight',
25+
'SP_ArrowUp',
26+
'SP_BrowserReload',
27+
'SP_BrowserStop',
28+
'SP_CommandLink',
29+
'SP_ComputerIcon',
30+
'SP_CustomBase',
31+
'SP_DesktopIcon',
32+
'SP_DialogApplyButton',
33+
'SP_DialogCancelButton',
34+
'SP_DialogCloseButton',
35+
'SP_DialogDiscardButton',
36+
'SP_DialogHelpButton',
37+
'SP_DialogNoButton',
38+
'SP_DialogOkButton',
39+
'SP_DialogOpenButton',
40+
'SP_DialogResetButton',
41+
'SP_DialogSaveButton',
42+
'SP_DialogYesButton',
43+
'SP_DirClosedIcon',
44+
'SP_DirHomeIcon',
45+
'SP_DirIcon',
46+
'SP_DirLinkIcon',
47+
'SP_DirOpenIcon',
48+
'SP_DockWidgetCloseButton',
49+
'SP_DriveCDIcon',
50+
'SP_DriveDVDIcon',
51+
'SP_DriveFDIcon',
52+
'SP_DriveHDIcon',
53+
'SP_DriveNetIcon',
54+
'SP_FileDialogBack',
55+
'SP_FileDialogContentsView',
56+
'SP_FileDialogDetailedView',
57+
'SP_FileDialogEnd',
58+
'SP_FileDialogInfoView',
59+
'SP_FileDialogListView',
60+
'SP_FileDialogNewFolder',
61+
'SP_FileDialogStart',
62+
'SP_FileDialogToParent',
63+
'SP_FileIcon',
64+
'SP_FileLinkIcon',
65+
'SP_MediaPause',
66+
'SP_MediaPlay',
67+
'SP_MediaSeekBackward',
68+
'SP_MediaSeekForward',
69+
'SP_MediaSkipBackward',
70+
'SP_MediaSkipForward',
71+
'SP_MediaStop',
72+
'SP_MediaVolume',
73+
'SP_MediaVolumeMuted',
74+
'SP_MessageBoxCritical',
75+
'SP_MessageBoxInformation',
76+
'SP_MessageBoxQuestion',
77+
'SP_MessageBoxWarning',
78+
'SP_TitleBarCloseButton',
79+
'SP_TitleBarContextHelpButton',
80+
'SP_TitleBarMaxButton',
81+
'SP_TitleBarMenuButton',
82+
'SP_TitleBarMinButton',
83+
'SP_TitleBarNormalButton',
84+
'SP_TitleBarShadeButton',
85+
'SP_TitleBarUnshadeButton',
86+
'SP_ToolBarHorizontalExtensionButton',
87+
'SP_ToolBarVerticalExtensionButton',
88+
'SP_TrashIcon',
89+
'SP_VistaShield'
90+
]
91+
92+
colSize = 4
93+
94+
layout = QGridLayout()
95+
96+
count = 0
97+
for i in icons:
98+
btn = QPushButton(i)
99+
btn.setIcon(self.style().standardIcon(getattr(QStyle, i)))
100+
101+
layout.addWidget(btn, count / colSize, count % colSize)
102+
count += 1
103+
104+
self.setLayout(layout)
105+
106+
107+
if __name__ == '__main__':
108+
app = QApplication(sys.argv)
109+
110+
dialog = Widget()
111+
dialog.show()
112+
113+
app.exec_()
114+
```
115+

docs/release-notes/release-notes-dev.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ Changes merged into master
66
| Jira Task | GitHub Issue | Type | Description |
77
|-----------|--------------|------|-------------|
88
| I04_1-167 | [#44](https://github.com/DiamondLightSource/PuckBarcodeReader/issues/44) | Minor | Added version number display |
9+
| I04_1-152 | [#48](https://github.com/DiamondLightSource/PuckBarcodeReader/issues/48) | Patch | Fixed missing icons |
10+
| I04_1-177 | [#46](https://github.com/DiamondLightSource/PuckBarcodeReader/issues/46) | Minor | Allow records for duplicate holder barcodes |
911

1012

1113
Change Types:

resources/icons/qr_code.ico

29.6 KB
Binary file not shown.

resources/icons/qr_code_32.png

1.22 KB
Loading

0 commit comments

Comments
 (0)