Skip to content

Commit 199825b

Browse files
committed
窗口里的扫描进度条终于不会闪了
增加任务栏进度显示 使用新的ping3库,不使用获取命令输出的方式 扫描结束后任务栏窗口会闪烁
1 parent d043ad7 commit 199825b

4 files changed

Lines changed: 108 additions & 24 deletions

File tree

info_gui.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ def __init__(self, master: Misc, data: ServerInfo):
1313
self.default_favicon = None
1414
self.data = data
1515
self.load_window_title()
16+
self.wm_resizable(True, True)
1617

1718
self.favicon = ttk.Label(self)
1819
self.MOTD = MOTD(self)
@@ -81,14 +82,14 @@ def load_data(self, data: ServerInfo):
8182
self.player_list.insert(END, player["name"])
8283
if len(data.players) > 0:
8384
self.tip = ToolTip(self.player_list, "UUID: " + data.players[0]["id"])
84-
self.player_list.bind("<Motion>", self.show_tip)
85+
self.player_list.bind("<Motion>", self.show_tip, add="+")
8586

8687
def show_tip(self, event: tk.Event):
8788
item = self.player_list.nearest(event.y)
8889
if item == -1:
8990
return
9091
uuid = [player for player in self.data.players if player["name"] == self.player_list.get(item)][0]['id']
91-
self.tip.hide_tip()
92+
self.tip.toplevel.destory()
9293
self.tip = ToolTip(self.player_list, "UUID: " + uuid)
9394

9495

main_gui.py

Lines changed: 54 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,20 @@
11
import re
22
import pyglet
33
from widgets import *
4+
from win_tool import *
5+
from ping3 import ping
46
from typing import Dict
57
from ttkbootstrap import Style
68
from info_gui import InfoWindow
7-
from subprocess import getoutput
89
from scanner import ServerScanner
910
from threading import Thread, Lock
1011
from tkinter import font, filedialog
1112
from base64 import b64decode, b64encode
1213
from pyperclip import copy as copy_clipboard
1314
from ttkbootstrap.scrolled import ScrolledFrame
14-
from json import load as json_load, dump as json_dump, JSONDecodeError
1515
from time import perf_counter, sleep, time, strftime
1616
from pickle import loads as pickle_loads, dumps as pickle_dumps
17+
from json import load as json_load, dump as json_dump, JSONDecodeError
1718
from win32con import MB_ICONWARNING, MB_YESNOCANCEL, IDYES, MB_ICONERROR, MB_OK, MB_YESNO, MB_ICONQUESTION, IDNO, \
1819
IDCANCEL
1920
from win32gui import MessageBox, FindWindow, FindWindowEx, GetParent, EnumChildWindows, GetWindowText, SetWindowText
@@ -30,12 +31,6 @@ def load_unifont():
3031
pyglet.font.add_file("assets/Unifont.otf")
3132

3233

33-
def ping_host(host: str) -> bool:
34-
cmd = f"ping -n 1 {host}"
35-
output = getoutput(cmd)
36-
return "丢失 = 0" in output
37-
38-
3934
def write_msg_window_buttons(left: str, right: str, timeout: float = 1.2):
4035
def callback(hwnd: int, _):
4136
if GetWindowText(hwnd) == "是(&Y)":
@@ -58,6 +53,16 @@ def callback(hwnd: int, _):
5853
break
5954

6055

56+
def get_hwnd_main_hwnd(hwnd: int):
57+
while True:
58+
print(hwnd, "P:", GetParent(hwnd))
59+
if GetParent(hwnd) != 0:
60+
hwnd = GetParent(hwnd)
61+
else:
62+
break
63+
return hwnd
64+
65+
6166
class GUI(ttk.Window):
6267
def __init__(self):
6368
super(GUI, self).__init__()
@@ -83,6 +88,7 @@ def config_root_window(self): # 设置窗体
8388
self.wm_title("MC服务器扫描器") # 设置标题
8489
self.style.theme_use("solar")
8590
self.wm_geometry("754x730")
91+
self.wm_resizable(False, False)
8692
Thread(target=self.wm_iconbitmap, args=("assets/icon.ico",)).start()
8793
Thread(target=self.place_window_center).start()
8894

@@ -541,7 +547,7 @@ def __init__(self, master: Misc, interval: float, text: str):
541547
self.last_value = 0
542548
self.last_update = time()
543549
self.speed_avg = []
544-
self._max = 0
550+
self.max_ = 0
545551
self.interval = interval
546552

547553
self.text = ttk.Label(self, text=text)
@@ -556,7 +562,7 @@ def reset(self, _max: int):
556562
self.last_value = 0
557563
self.last_update = time()
558564
self.speed_avg.clear()
559-
self._max = _max
565+
self.max_ = _max
560566
self.progress_text.configure(text="0 ports/s")
561567
self.progress.set_percentage(0, "0%")
562568

@@ -573,7 +579,7 @@ def update_now(self, value: float):
573579
elif len(self.speed_avg) == 0:
574580
self.speed_avg.append(0)
575581

576-
percentage = value / self._max
582+
percentage = value / self.max_
577583
self.progress.set_percentage(percentage, f"{round(percentage * 100, 2)}%")
578584
self.update_progress_text(sum(self.speed_avg) / len(self.speed_avg))
579585

@@ -582,7 +588,7 @@ def update_now(self, value: float):
582588
self.last_update = time()
583589

584590
def finish(self):
585-
self.update_now(self._max)
591+
self.update_now(self.max_)
586592
self.update_progress_text(0)
587593

588594

@@ -594,27 +600,38 @@ def __init__(self, master: Misc, text: str = "0%"):
594600
self.bind("<<ThemeChanged>>", self.change_color)
595601
self.percentage = 0
596602
self.text = text
597-
self.redraw()
603+
self.now_elements = []
604+
self.last_elements = []
605+
606+
self.text_id = self.create_text(self.winfo_width() // 2, 13, text=self.text, fill=self.color.fg)
607+
self.last_elements.append(self.text_id)
598608

599609
def change_color(self, *_):
600610
self.color = Style().colors
601611
self.redraw()
602612

603613
def redraw(self, *_):
604-
self.delete(ALL)
614+
self.now_elements.clear()
605615
width = self.winfo_width()
606616
bar_x = int((width - 4) * self.percentage)
607617
if bar_x == 1:
608-
self.create_line(1, 1, 1, 26, fill=self.color.success)
618+
self.now_elements.append(self.create_line(1, 1, 1, 26, fill=self.color.success))
609619
elif bar_x > 1:
610-
self.create_rectangle(1, 1, bar_x, 26 - 2, fill=self.color.success, outline=self.color.success) # 06B025
620+
self.now_elements.append(self.create_rectangle(1, 1, bar_x, 26 - 2, fill=self.color.success,
621+
outline=self.color.success))
622+
623+
self.now_elements.append(self.create_rectangle(0, 0, width - 1, 26 - 1, outline=self.color.border))
624+
self.text_id = self.create_text(width // 2, 13, text=self.text, fill=self.color.fg)
625+
self.now_elements.append(self.text_id)
611626

612-
self.create_rectangle(0, 0, width - 1, 26 - 1, outline=self.color.border)
613-
self.create_text(width // 2, 13, text=self.text, fill=self.color.fg)
627+
if self.last_elements:
628+
self.delete(*self.last_elements)
629+
self.last_elements = self.now_elements.copy()
614630

615631
def set_percentage(self, percentage: float, text: str = None):
616632
self.percentage = percentage
617633
self.text = text if text is not None else self.text
634+
self.itemconfig(self.text_id, text=self.text)
618635
self.redraw()
619636

620637

@@ -804,6 +821,8 @@ def __init__(self, master: Misc, logger: Logger, server_list: ServerList):
804821
self.callback_lock = Lock()
805822
self.progress_var = 0
806823
self.callback_workers = 0
824+
self.taskbar = None
825+
self.after(100, self.taskbar_create)
807826

808827
# 进度条
809828
self.progress_bar = InfoProgressBar(self, interval=0.05, text="扫描进度: ")
@@ -832,7 +851,7 @@ def __init__(self, master: Misc, logger: Logger, server_list: ServerList):
832851

833852
# 扫描控制 Frame
834853
self.buttons = ttk.Frame(self)
835-
self.start_button = ttk.Button(self.buttons, text="开始扫描", command=self.start_scan)
854+
self.start_button = ttk.Button(self.buttons, text="开始扫描", command=self.start_scan, state=DISABLED)
836855
self.pause_button = PauseButton(self.buttons, self.resume_scan, self.pause_scan, state=DISABLED)
837856
self.stop_button = ttk.Button(self.buttons, text="停止", command=self.stop_scan, state=DISABLED)
838857

@@ -841,12 +860,17 @@ def __init__(self, master: Misc, logger: Logger, server_list: ServerList):
841860
self.pause_button.pack(fill=X, expand=True, pady=2)
842861
self.stop_button.pack(fill=X, expand=True, pady=2)
843862

863+
def taskbar_create(self):
864+
self.taskbar = TaskbarApi(FindWindow("TkTopLevel", "MC服务器扫描器"))
865+
self.start_button.configure(state=NORMAL)
866+
844867
def callback(self, info: Any):
845868
if not self.in_scan:
846869
return
847870
with self.callback_lock:
848871
self.progress_var += 1
849872
self.progress_bar.update_progress(self.progress_var)
873+
self.taskbar.SetProgressValue(self.progress_var, self.progress_bar.max_)
850874
if isinstance(info, ServerInfo):
851875
self.server_list.add_server(info)
852876
self.logger.log(INFO, f"[{info.port}]:", "检测到MC服务器")
@@ -877,6 +901,7 @@ def start_scan(self, start: int = None, stop: int = None): # 20500 - 25000
877901
self.scan_obj.config(host, timeout, thread_num)
878902
Thread(target=self.scan_obj.run, args=(range(start, stop), self.callback)).start()
879903
Thread(target=self.check_over_thread, daemon=True).start()
904+
self.taskbar.SetProgressState(TBPFLAG.TBPF_NORMAL)
880905

881906
def pause_scan(self):
882907
def task():
@@ -890,6 +915,7 @@ def task():
890915
self.pause_button.configure(state=NORMAL)
891916

892917
Thread(target=task, daemon=True).start()
918+
self.taskbar.SetProgressState(TBPFLAG.TBPF_PAUSED)
893919

894920
def resume_scan(self):
895921
def task():
@@ -902,6 +928,7 @@ def task():
902928
self.pause_button.configure(state=NORMAL)
903929

904930
Thread(target=task, daemon=True).start()
931+
self.taskbar.SetProgressState(TBPFLAG.TBPF_NORMAL)
905932

906933
def stop_scan(self):
907934
if not self.in_scan:
@@ -913,14 +940,17 @@ def stop_scan(self):
913940
def stop_task():
914941
self.in_scan = False
915942
self.scan_obj.stop()
943+
self.logger.log(INFO, "停止扫描")
916944
while self.scan_obj.worker_count != 0:
917945
sleep(0.1)
918946
self.logger.log(INFO, "等待线程结束, 剩余工作线程线程数量:", self.scan_obj.worker_count)
919947
self.logger.log(INFO, "线程已全部结束")
920948
self.start_button.configure(state=NORMAL)
949+
self.taskbar.SetProgressState(TBPFLAG.TBPF_NOPROGRESS)
921950
self.progress_stop()
922951

923952
Thread(target=stop_task).start()
953+
self.taskbar.SetProgressState(TBPFLAG.TBPF_INDETERMINATE)
924954

925955
def check_over_thread(self):
926956
if not self.in_scan:
@@ -934,10 +964,11 @@ def check_over_thread(self):
934964
self.pause_button.configure(state=DISABLED)
935965
self.start_button.configure(state=NORMAL)
936966
self.progress_stop()
967+
FlashWindowCount(FindWindow("TkTopLevel", "MC服务器扫描器"))
937968

938969
def progress_stop(self):
939970
self.progress_bar.update_now(self.progress_var)
940-
self.progress_bar.finish()
971+
# self.progress_bar.finish()
941972

942973
def check_host(self, host: str) -> bool:
943974
self.logger.log(INFO, f"检测域名 [{host}] ...")
@@ -952,8 +983,9 @@ def check_host(self, host: str) -> bool:
952983
return False
953984

954985
self.logger.log(INFO, "开始ping测试...")
955-
if ping_host(host):
956-
self.logger.log(INFO, "域名存活")
986+
delay = ping(host)
987+
if delay is not None:
988+
self.logger.log(INFO, f"域名存活, 延迟: {round(delay * 1000, 2)} ms")
957989
return True
958990
else:
959991
self.logger.log(ERROR, "域名无法连接")

scanner.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,11 @@ def config(self, host: str, timeout: float = 0.7, thread_num: int = 256):
3636
self.host = host
3737

3838
def run(self, port_range: range, callback: object):
39+
while not self.work_queue.empty():
40+
try:
41+
self.work_queue.get(block=False)
42+
except Empty:
43+
break
3944
self.in_scan = True
4045
self.callback = callback
4146
for port in port_range:

win_tool.py

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
from enum import Enum
2+
import comtypes.client as cc
3+
from win32con import FLASHW_ALL
4+
from win32gui import FlashWindowEx
5+
cc.GetModule(r"assets\TaskbarLib.tlb")
6+
import comtypes.gen.TaskbarLib as TaskbarLib
7+
8+
9+
class TBPFLAG(Enum):
10+
TBPF_NOPROGRESS = 0x00000000
11+
TBPF_INDETERMINATE = 0x00000001
12+
TBPF_NORMAL = 0x00000002
13+
TBPF_ERROR = 0x00000004
14+
TBPF_PAUSED = 0x00000008
15+
16+
17+
class TaskbarApi:
18+
def __init__(self, hwnd: int):
19+
self.hwnd = hwnd
20+
self.taskbar = cc.CreateObject(
21+
"{56FDF344-FD6D-11d0-958A-006097C9A090}",
22+
interface=TaskbarLib.ITaskbarList3)
23+
self.taskbar.HrInit()
24+
25+
self.taskbar.DeleteTab(hwnd)
26+
self.taskbar.AddTab(hwnd)
27+
self.taskbar.ActivateTab(hwnd)
28+
29+
def SetProgressState(self, state: TBPFLAG):
30+
self.taskbar.SetProgressState(self.hwnd, state.value)
31+
32+
def SetProgressValue(self, progress: int, _max: int):
33+
self.taskbar.SetProgressValue(self.hwnd, progress, _max)
34+
35+
36+
class FLASHW(Enum):
37+
FLASHW_STOP = 0x00000000
38+
FLASHW_CAPTION = 0x00000001
39+
FLASHW_TRAY = 0x00000002
40+
FLASHW_ALL = 0x00000003
41+
FLASHW_TIMER = 0x00000004
42+
FLASHW_TIMERNOFG = 0x0000000C
43+
44+
45+
def FlashWindowCount(hwnd: int, count: int = 3, interval: float = 0.5, flags: FLASHW = FLASHW.FLASHW_ALL):
46+
FlashWindowEx(hwnd, flags.value, count, int(interval * 1000))

0 commit comments

Comments
 (0)