#python #tkinter
Вопрос:
Я пытаюсь реализовать простой шестнадцатеричный просмотрщик, используя три Text()
поля, которые настроены на одновременную прокрутку.
Однако, похоже, что происходит какой-то «дрейф», и в какой-то момент первая коробка теряет выравнивание с двумя другими. Я, кажется, не могу понять, почему.
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()
Сначала все выровнено правильно:
Однако через некоторое время наблюдается видимое несоответствие между первым столбцом и двумя другими:
Сначала я подумал, что это может быть связано с высотой линий, но установка spacing1
spacing2
, и spacing3
не помогла. Проблема также сохраняется, если я заменю все символы, не являющиеся пробелами, одним символом, таким как » O » (чтобы убедиться, что все символы имеют одинаковую высоту).
Как я могу гарантировать, что все три поля будут выровнены?
Комментарии:
1. Я провел некоторое тестирование, и
textbox_address
у1026
меня есть строки, в то время как у обоихtextbox_ascii
иtextbox.hex
есть1025
строки. Я дам вам знать, если выясню, почему это происходит, но, по крайней мере, есть причина вашей проблемы.
Ответ №1:
Внутри _populate_address_area
есть for
петля: for i in range(num_lines 1):
. Это и есть причина проблемы. Использование num_lines 1
добавляет слишком много линзе textbox_address
. Чтобы исправить это, есть два варианта: удалить 1
или использовать for i in range(1, num_lines 1):
. В любом случае, textbox_address
будет иметь правильное количество строк.
Комментарии:
1. Спасибо! Не могу поверить, что это было так просто. Для полноты картины я добавлю, что мне пришлось настроить
num_lines
его так, чтобы он содержал дополнительную строку на случайnum_bytes
, если она не кратнаBYTES_PER_ROW
.