基于Python Arcade库的文本框滚动功能实现求助
Hey there! Let's fix that text overflow and scrolling issue in your Arcade text box. The main gap right now is that your display class draws the entire text string no matter the box width—we need to track which portion of the text should be visible, and adjust that portion when the cursor moves outside the visible area.
Key Concepts to Make This Work
- Calculate the width of a single character (using Arcade's built-in text width tools) to know when text exceeds the box.
- Add a
scroll_offsetvariable to your display class to track the starting index of the visible text. - Adjust
scroll_offsetdynamically based on the cursor position to keep the cursor within the text box bounds. - Only draw the substring of text that fits within the box, starting from
scroll_offset.
Modified Code Implementation
First, update your Text Display Class to handle scrolling:
class TextDisplay: def __init__(self, x, y, width, char_limit, font_size=24): self.x = x self.y = y self.width = width self.font_size = font_size self.highlighted = False self.text = "" self.symbol = "" self.char_limit = char_limit # Calculate width of a single character (using 'A' as a baseline) self.char_width = arcade.get_text_width("A", font_size=font_size) # Max number of visible characters in the box self.max_visible_chars = int(self.width // self.char_width) # Track the starting index of visible text self.scroll_offset = 0 def update(self, delta_time, text, cursor_index): self.text = text # Adjust scroll offset to keep cursor visible self.adjust_scroll_offset(cursor_index) def adjust_scroll_offset(self, cursor_index): # If cursor is to the right of visible area, shift scroll right if cursor_index >= self.scroll_offset + self.max_visible_chars: self.scroll_offset = cursor_index - self.max_visible_chars + 1 # Don't let offset go negative or beyond text length self.scroll_offset = max(0, min(self.scroll_offset, len(self.text))) # If cursor is to the left of visible area, shift scroll left elif cursor_index < self.scroll_offset: self.scroll_offset = cursor_index def draw_text(self): # Get the visible substring of text visible_text = self.text[self.scroll_offset:self.scroll_offset + self.max_visible_chars] # Draw the visible text (plus cursor if highlighted) draw_text = visible_text + (self.symbol if self.highlighted else "") arcade.draw_text( draw_text, self.x - self.width/2, self.y, arcade.color.BLACK, font_size=self.font_size, anchor_y="center" )
Then, update your Text Box Class to pass the cursor index instead of just the symbol to the display:
def update(self, delta_time, keys_pressed): if self.text_display.highlighted: text, cursor_index = self.text_storage.update(delta_time, keys_pressed) # Update symbol based on blink state from storage self.text_display.symbol = self.text_storage.cursor_symbol self.text_display.update(delta_time, text, cursor_index)
And tweak your Text Storage Class to return the cursor index (instead of just the symbol) and fix text insertion/backspace logic:
def update(self, delta_time, keys_pressed): self.time += delta_time self.blink_cursor() for key in keys_pressed: if key == arcade.key.BACKSPACE: if len(self.text) > 0: # Adjust cursor if deleting the character before it if self.cursor_index > 0: self.text = self.text[:self.cursor_index-1] + self.text[self.cursor_index:] self.cursor_index -= 1 elif key == arcade.key.LEFT: if self.cursor_index > 0: self.cursor_index -= 1 elif key == arcade.key.RIGHT: if self.cursor_index < len(self.text): self.cursor_index += 1 else: if len(self.text) < self.char_limit: # Insert character at cursor position instead of appending self.text = self.text[:self.cursor_index] + chr(key) + self.text[self.cursor_index:] self.cursor_index += 1 # Return text and cursor index for display scrolling logic return self.text, self.cursor_index
How This Works
- Character Width Calculation: We use
arcade.get_text_widthto find the width of a standard character, which lets us compute exactly how many characters fit in the text box. - Scroll Offset Adjustment: The
adjust_scroll_offsetmethod checks if the cursor is outside the current visible text range. If it is, we shift thescroll_offsetto bring the cursor back into view. - Visible Text Drawing: Instead of drawing the full text, we slice it to only include characters starting from
scroll_offsetup to the maximum visible count. - Cursor Handling: We fixed text insertion to add characters at the cursor position (instead of always appending) and adjusted backspace to update the cursor position correctly when deleting text.
Now when you type text longer than the box width, the text will scroll automatically as you type, and pressing left/right arrows will shift the visible text to keep the cursor in view.
内容的提问来源于stack exchange,提问作者Wamiq Ur Rehman

