Skip to content

Commit 0cfbd42

Browse files
committed
Add New Features (Experimental)
Ctrl + C로 글 검색 내용 복사 가능 Ctrl + F로 검색창에 포커스 가능 (크롬창의 Ctrl + F 와 동일한 기능)
1 parent c5b4a33 commit 0cfbd42

File tree

4 files changed

+226
-7
lines changed

4 files changed

+226
-7
lines changed

main.py

Lines changed: 112 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -100,9 +100,9 @@ def run(self):
100100
self.QTableWidgetSetSort.emit(True)
101101
# mutex.unlock()
102102

103-
def stop(self):
104-
self.quit()
105-
self.wait(3000)
103+
# def stop(self):
104+
# self.quit()
105+
# self.wait(3000)
106106

107107
# 모듈화에 문제가 생겨서 우선 하드 코딩
108108

@@ -113,7 +113,7 @@ def resource_path(relative_path):
113113
return os.path.join(base_path, relative_path)
114114

115115

116-
# Main UI Load
116+
# Main UI Compile & Load
117117

118118
# fmt: off
119119

@@ -124,6 +124,52 @@ def resource_path(relative_path):
124124

125125
# fmt: on
126126

127+
# SearchWindow
128+
129+
130+
class SearchWindow(QMainWindow, Ui_MainWindow):
131+
filtering = pyqtSignal(str) # 필터링 시그널
132+
133+
# 100,100 창으로 설정
134+
def __init__(self):
135+
super().__init__()
136+
self.initUI()
137+
138+
def txt_id_enter(self):
139+
# 현재 검색값을 시그널로 Main윈도우에 넘기기
140+
self.filtering.emit(self.txt_keyword.text())
141+
142+
def initUI(self):
143+
self.setWindowTitle('Search Window')
144+
145+
# 입력창 추가
146+
self.txt_keyword = QLineEdit(self)
147+
self.txt_keyword.move(0, 0)
148+
self.txt_keyword.resize(200, 20)
149+
150+
# QlineEdit CSS 추가
151+
self.setStyleSheet(
152+
r"QLineEdit { border: 4px solid padding: 4px } QLineEdit: focus{ border: 4px solid rgb(0, 170, 255) }")
153+
154+
# 타이틀창 간소화 하기
155+
self.setWindowFlags(Qt.WindowTitleHint | Qt.WindowCloseButtonHint)
156+
157+
# 아이콘 main.ico 로 창 설정
158+
self.setWindowIcon(QIcon(resource_path('main.ico')))
159+
160+
# txt_id 엔터 시그널 연결
161+
self.txt_keyword.returnPressed.connect(self.txt_id_enter)
162+
163+
# self.move(300, 300)
164+
self.resize(200, 20)
165+
self.show()
166+
167+
# 엔터키 누르면 종료
168+
def keyPressEvent(self, e):
169+
# esc 누르면 종료
170+
if e.key() == QtCore.Qt.Key_Escape:
171+
self.close()
172+
127173

128174
class Main(QMainWindow, Ui_MainWindow):
129175
def __init__(self):
@@ -135,10 +181,17 @@ def __init__(self):
135181
# style = f"QComboBox::down-arrow {{image: url('{resource_path('resource/arrow.png')}');}}"
136182
# self.comboBox.setStyleSheet(style)
137183
# print(style)
184+
185+
# 이전 검색 기록 기억
186+
# 파이썬에선 멤버 변수 선언시 생성자에 적어야함.
187+
# self를 안적으면 C#이나 Java의 객체 static 선언하고 똑같다고 보면 됨.
188+
self.prev_item = ""
189+
self.prev_idx = 0
190+
138191
self.show()
139192

140193
def initializer(self):
141-
self.setTableWidget() # Table Widget Column 폭 Fixed
194+
self.set_table_widget() # Table Widget Column 폭 Fixed
142195
self.set_only_int() # 반복횟수는 숫자만 입력할 수 있도록 고정
143196
self.load_data('user_save.dat')
144197

@@ -177,7 +230,7 @@ def set_only_int(self):
177230
self.onlyInt = QIntValidator()
178231
self.txt_repeat.setValidator(self.onlyInt)
179232

180-
def setTableWidget(self):
233+
def set_table_widget(self):
181234
self.articleView.setEditTriggers(
182235
QAbstractItemView.NoEditTriggers) # TableWidget 읽기 전용 설정
183236
self.articleView.setColumnWidth(0, 60) # 글 번호
@@ -188,7 +241,7 @@ def setTableWidget(self):
188241
self.articleView.setColumnWidth(5, 40) # 조회
189242
self.articleView.setColumnWidth(6, 40) # 추천
190243

191-
def setTableAutoSize(self):
244+
def set_table_autosize(self):
192245
header = self.articleView.horizontalHeader()
193246
# 성능을 위해 이제 자동 컬럼조정은 사용하지 않는다.
194247
# header.setSectionResizeMode(0, QHeaderView.ResizeToContents)
@@ -325,6 +378,58 @@ def on_finished(self):
325378
thread_dead = True
326379
pass
327380

381+
@ pyqtSlot(str)
382+
def filtering(self, keyword):
383+
# Clear current selection.
384+
self.articleView.setCurrentItem(None)
385+
386+
if not keyword:
387+
# Empty string, don't search.
388+
return
389+
390+
if self.prev_item == keyword:
391+
# 같은 키워드가 들어오면 다음 아이템으로 이동해서 확인
392+
self.prev_idx += 1
393+
else:
394+
# 키워드가 달라지면 처음부터 다시 검색
395+
self.prev_idx = 0
396+
397+
matching_items = self.articleView.findItems(keyword, Qt.MatchContains)
398+
matching_item_cnt = len(matching_items)
399+
if matching_items:
400+
# We have found something.
401+
if self.prev_idx >= matching_item_cnt:
402+
# 처음부터 다시 검색
403+
self.prev_idx = 0
404+
item = matching_items[self.prev_idx] # Take the first.
405+
self.prev_item = keyword # 검색한 내용 기억
406+
self.articleView.setCurrentItem(item)
407+
408+
# print(keyword)
409+
410+
def keyPressEvent(self, event):
411+
# Ctrl + C 누른 경우 Table의 내용 복사
412+
# https://stackoverflow.com/questions/60715462/how-to-copy-and-paste-multiple-cells-in-qtablewidget-in-pyqt5
413+
if event.key() == Qt.Key.Key_C and (event.modifiers() & Qt.KeyboardModifier.ControlModifier):
414+
copied_cells = sorted(self.articleView.selectedIndexes())
415+
416+
copy_text = ''
417+
max_column = copied_cells[-1].column()
418+
for c in copied_cells:
419+
copy_text += self.articleView.item(c.row(), c.column()).text()
420+
if c.column() == max_column:
421+
copy_text += '\n'
422+
else:
423+
copy_text += '\t'
424+
425+
QApplication.clipboard().setText(copy_text)
426+
427+
# Ctrl + F 누른 경우 검색 창 (필터링 창) 열기
428+
elif event.key() == Qt.Key.Key_F and (event.modifiers() & Qt.KeyboardModifier.ControlModifier):
429+
self.searchWindow = SearchWindow()
430+
self.searchWindow.filtering.connect(self.filtering)
431+
self.searchWindow.show()
432+
328433

329434
app = QApplication([])
330435
main = Main()
0 Bytes
Binary file not shown.
File renamed without changes.

test.py

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
from PyQt5.QtCore import *
2+
from PyQt5.QtWidgets import *
3+
4+
5+
class MyMainGUI(QDialog):
6+
def __init__(self, parent=None):
7+
super().__init__(parent)
8+
9+
self.qtxt1 = QTextEdit(self)
10+
self.btn1 = QPushButton("Start", self)
11+
self.btn2 = QPushButton("Stop", self)
12+
self.btn3 = QPushButton("add 100", self)
13+
self.btn4 = QPushButton("send instance", self)
14+
15+
vbox = QVBoxLayout()
16+
vbox.addWidget(self.qtxt1)
17+
vbox.addWidget(self.btn1)
18+
vbox.addWidget(self.btn2)
19+
vbox.addWidget(self.btn3)
20+
vbox.addWidget(self.btn4)
21+
self.setLayout(vbox)
22+
23+
self.setGeometry(100, 50, 300, 300)
24+
25+
26+
class Test:
27+
def __init__(self):
28+
name = ""
29+
30+
31+
class MyMain(MyMainGUI):
32+
add_sec_signal = pyqtSignal()
33+
send_instance_singal = pyqtSignal("PyQt_PyObject")
34+
35+
def __init__(self, parent=None):
36+
super().__init__(parent)
37+
38+
self.btn1.clicked.connect(self.time_start)
39+
self.btn2.clicked.connect(self.time_stop)
40+
self.btn3.clicked.connect(self.add_sec)
41+
self.btn4.clicked.connect(self.send_instance)
42+
43+
self.th = Worker(parent=self)
44+
# custom signal from worker thread to main thread
45+
self.th.sec_changed.connect(self.time_update)
46+
47+
# custom signal from main thread to worker thread
48+
self.add_sec_signal.connect(self.th.add_sec)
49+
self.send_instance_singal.connect(self.th.recive_instance_singal)
50+
self.show()
51+
52+
@pyqtSlot()
53+
def time_start(self):
54+
self.th.start()
55+
self.th.working = True
56+
57+
@pyqtSlot()
58+
def time_stop(self):
59+
self.th.working = False
60+
self.th.quit()
61+
62+
@pyqtSlot()
63+
def add_sec(self):
64+
print(".... add singal emit....")
65+
self.add_sec_signal.emit()
66+
67+
@pyqtSlot(str)
68+
def time_update(self, msg):
69+
self.qtxt1.append(msg)
70+
71+
@pyqtSlot()
72+
def send_instance(self):
73+
t1 = Test()
74+
t1.name = "SuperPower!!!"
75+
self.send_instance_singal.emit(t1)
76+
77+
78+
class Worker(QThread):
79+
sec_changed = pyqtSignal(str)
80+
81+
def __init__(self, sec=0, parent=None):
82+
super().__init__()
83+
self.main = parent
84+
self.working = True
85+
self.sec = sec
86+
87+
# self.main.add_sec_signal.connect(self.add_sec) # 이것도 작동함. # custom signal from main thread to worker thread
88+
89+
def __del__(self):
90+
print(".... end thread.....")
91+
self.wait()
92+
93+
def run(self):
94+
while self.working:
95+
self.sec_changed.emit('time (secs):{}'.format(self.sec))
96+
self.sleep(1)
97+
self.sec += 1
98+
99+
@pyqtSlot()
100+
def add_sec(self):
101+
print("add_sec....")
102+
self.sec += 100
103+
104+
@pyqtSlot("PyQt_PyObject") # @pyqtSlot(object) 도 가능..
105+
def recive_instance_singal(self, inst):
106+
print(inst.name)
107+
108+
109+
if __name__ == "__main__":
110+
import sys
111+
112+
app = QApplication(sys.argv)
113+
form = MyMain()
114+
app.exec_()

0 commit comments

Comments
 (0)