Tkinter开发HEX Viewer时同步滚动Text控件出现对齐偏移问题
Tkinter HEX Viewer多文本框同步滚动错位修复方案
问题复现
通过三个独立Text控件分别展示地址、十六进制值、ASCII字符,绑定了统一的滚动逻辑,但滚动一段时间后三列内容出现累计偏移,排查行高参数、字符一致性后问题仍存在。
原实现代码
import tkinter as tk import os def chunker(seq, size: int): return (seq[pos:pos + size] for pos in range(0, len(seq), size)) TAG_JUSTIFY_RIGHT = 'justify_right' class Application(tk.Frame): BYTES_PER_ROW = 16 def __init__(self, parent = None): tk.Frame.__init__(self, parent) self.textbox_address = tk.Text(self, width = 17, padx = 10, wrap = tk.NONE, bd = 0) self.textbox_address.pack(side = tk.LEFT, fill=tk.Y, expand = False) self.textbox_address.tag_configure(TAG_JUSTIFY_RIGHT, justify = tk.RIGHT) self.textbox_hex = tk.Text(self, width = 47, padx = 10, wrap = tk.NONE, bd = 0) self.textbox_hex.pack(side = tk.LEFT, fill = tk.Y, expand = False) self.textbox_ascii = tk.Text(self, width = 17, padx = 10, wrap = tk.NONE, bd = 0) self.textbox_ascii.pack(side = tk.LEFT, fill = tk.Y, expand = False) self.textboxes = [self.textbox_address, self.textbox_hex, self.textbox_ascii] self.scrollbar = tk.Scrollbar(self) self.scrollbar.pack(side = tk.RIGHT, fill = tk.Y, expand = False) self.scrollbar['command'] = self._on_scrollbar for textbox in self.textboxes: textbox['yscrollcommand'] = self._on_textscroll self.pack(fill = tk.BOTH, expand = True, side = tk.RIGHT) def _on_scrollbar(self, *args) -> None: for textbox in self.textboxes: textbox.yview(*args) def _on_textscroll(self, *args) -> None: self.scrollbar.set(*args) self._on_scrollbar('moveto', args[0]) def _populate_address_area(self, num_bytes: int) -> None: num_lines = num_bytes // self.BYTES_PER_ROW chars_per_byte = 2 format_pad_len = 8 * chars_per_byte for i in range(num_lines + 1): base_address = format(i * self.BYTES_PER_ROW, 'X').rjust(format_pad_len, '0') self.textbox_address.insert(tk.END, f"{base_address}\n") self.textbox_address.tag_add(TAG_JUSTIFY_RIGHT, 1.0, tk.END) self.textbox_address.config(state = tk.DISABLED) def populate_hex_view(self, byte_arr: bytes) -> None: self._populate_address_area(len(byte_arr)) for chunk in chunker(byte_arr, self.BYTES_PER_ROW): hex_format = chunk.hex(" ") self.textbox_hex.insert(tk.END, f"{hex_format}\n") ascii_format = "".join([chr(i) if 32 <= i <= 127 else "." for i in chunk]) self.textbox_ascii.insert(tk.END, f"{ascii_format}\n") self.textbox_hex.config(state = tk.DISABLED) self.textbox_ascii.config(state = tk.DISABLED) if __name__ == "__main__": root = tk.Tk() root.title('Hex View') app = Application(parent = root) app.populate_hex_view(bytearray(os.urandom(0x4000))) root.mainloop()
问题现象
- 初始状态对齐正常:

- 滚动后出现偏移:

修复方案
问题根源
三个Text控件未强制使用统一等宽字体,Tkinter默认字体渲染会因为每行的字符构成差异产生微小的行高误差,多次滚动后误差累计就会出现明显错位。
具体修改
在初始化Text控件时,给所有控件设置相同的等宽字体参数,同时统一设置spacing、padx等边距参数,确保每行的渲染高度完全一致。
修改__init__方法中的Text控件初始化代码如下:
# 统一设置等宽字体,可根据系统调整为Consolas、Monaco等其他等宽字体 FONT_CONFIG = ('Courier New', 10) self.textbox_address = tk.Text(self, width = 17, padx = 10, wrap = tk.NONE, bd = 0, font=FONT_CONFIG, spacing1=0, spacing2=0, spacing3=0) self.textbox_address.pack(side = tk.LEFT, fill=tk.Y, expand = False) self.textbox_address.tag_configure(TAG_JUSTIFY_RIGHT, justify = tk.RIGHT) self.textbox_hex = tk.Text(self, width = 47, padx = 10, wrap = tk.NONE, bd = 0, font=FONT_CONFIG, spacing1=0, spacing2=0, spacing3=0) self.textbox_hex.pack(side = tk.LEFT, fill = tk.Y, expand = False) self.textbox_ascii = tk.Text(self, width = 17, padx = 10, wrap = tk.NONE, bd = 0, font=FONT_CONFIG, spacing1=0, spacing2=0, spacing3=0) self.textbox_ascii.pack(side = tk.LEFT, fill = tk.Y, expand = False)
如果仍有轻微偏移,可以进一步修改同步滚动逻辑,强制三个控件的行号完全对齐:
def _on_scrollbar(self, *args) -> None: # 先获取第一个控件的当前行位置,其他控件强制对齐到相同行 first_visible = self.textbox_address.yview()[0] for textbox in self.textboxes: textbox.yview_moveto(first_visible)
内容的提问来源于stack exchange,提问作者Dvd848
相关产品推荐
相关产品推荐

