【问题标题】:Qbasic Highlighted MenuQbasic 高亮菜单
【发布时间】:2022-05-03 20:34:56
【问题描述】:

有没有人有示例代码或说明来完成这项工作?我只是无法完成使用箭头键和 enter 进行选择的突出显示菜单。提前致谢!

我希望通过为每个选项绘制框,并在选择选项时为文本着色的同时用颜色重新绘制框来实现这一点。我只是不确定如何设计一个循环来实现这一点。我对INKEY$ 函数和SELECT CASE 语句很满意,但我不知道如何考虑它们。

【问题讨论】:

    标签: loops menu highlight qbasic


    【解决方案1】:

    突出显示的菜单将绘制菜单并等待循环中的按键或使用SLEEP。一种常见的替代方法是简单地更改前几个字母之一的文本颜色,通知用户按下相应的键以选择相应的菜单选项。例如,“Quit”中的字母 Q 和“New Game”中的字母 N 与该行中其他文本的颜色不同。

    但是,您要求使用箭头键,显然您不想那样做。如何突出显示当前菜单项取决于所使用的屏幕模式。屏幕模式 11、12 和 13 不允许您指定背景颜色,并且我无法让 DOSBox 使用模式 7、8 和 9 渲染背景。作为解决此问题的方法,您可以改为简单地在当前选择旁边绘制一个框并擦除该框(绘制一个黑色或任何屏幕背景颜色)。或者您可以只使用星号来避免图形/文本大小问题并简化代码。这是一个带有箭头键、WASD 键和 Vim 样式键(H=Left、J=Down、K=Up、L=Right)的框样式示例,假设使用的是 US-QWERTY 键盘。如果您只需要箭头键,那么您只需将第一个(外部)SELECT CASE...END SELECT 块更改为简单的 IF LEFT$(k$, 1) = CHR$(0) THEN...END IF,同时保留与扩展键一起使用的内部 SELECT CASE...END SELECT 块。

    'size% is used in the selIncDec subroutine.
    DIM text$(0 TO 3)
    DIM SHARED size%
    size% = UBOUND(text$) - LBOUND(text$) + 1
    
    selected% = 0
    
    text$(0) = "Example 1"
    text$(1) = "Example 2"
    text$(2) = "Example 3"
    text$(3) = "Example 4"
    
    SCREEN 12
    
    ' Width and height of a text cell in pixels.
    ' I use 8x8 text cells for max screen compatibility, despite 8x16 looking better.
    xpxText% = 8
    ypxText% = 8
    
    ' See the documentation for SCREEN to determine which screen sizes are
    ' available with the screen mode you want to use.
    ' 80x60 for mode 12 results in 8x8 text cells. 80x30 results in 8x16 text cells.
    WIDTH 80, 60
    
    DO
        LOCATE 1, 1
        FOR i% = LBOUND(text$) TO UBOUND(text$)
            PRINT TAB(3); text$(i%)
            '    selected% = i%
            ' is an equality comparison, resulting in -1 for true and 0 for false.
            ' If false, -(0) * 2 = 0; if true, -(-1) * 2 = 2.
            LINE (0, i% * ypxText%)-STEP(xpxText% - 1, xpxText% - 1), -(selected% = i%) * 2, BF
        NEXT i%
    
        SLEEP
        k$ = INKEY$
        SELECT CASE UCASE$(LEFT$(k$, 1))
          ' Left -- does nothing
          CASE "H", "A"
    
          ' Right -- does nothing
          CASE "L", "D"
    
          ' Up
          CASE "K", "W"
            CALL selIncDec(selected%, -1)
    
          ' Down
          CASE "J", "S"
            CALL selIncDec(selected%, 1)
    
          ' Enter key
          CASE CHR$(13)
            EXIT DO
    
          ' Extended key, such as arrows.
          CASE CHR$(0)
            SELECT CASE RIGHT$(k$, 1)
              ' Left
              CASE "K"
    
              ' Right
              CASE "M"
    
              ' Up
              CASE "H"
                CALL selIncDec(selected%, -1)
    
              ' Down
              CASE "P"
                CALL selIncDec(selected%, 1)
            END SELECT
        END SELECT
    LOOP
    
    PRINT USING "You selected option #"; selected% + 1
    
    END
    
    SUB selIncDec (selected%, amtInc%)
        selected% = selected% + amtInc%
        IF selected% >= size% THEN
            selected% = selected% - size%
        ELSEIF selected% < 0 THEN
            selected% = selected% + size%
        END IF
    END SUB
    

    如果您使用的屏幕模式支持背景颜色或以某种形式突出显示,例如屏幕 0,则您可能可以在文本模式下简单地“突出显示”整行的背景。您不需要指定屏幕的宽度以使“反向视频”效果充当突出显示,但是当您突出显示整行而不是仅突出显示文本时看起来会更好。打印该菜单项后,只需将颜色更改回默认值并照常继续打印。下面显示了对上述代码的一些更改(屏幕模式、屏幕宽度设置和菜单显示代码),但其他方面保持不变:

    SCREEN 0
    '8x8 text cells in SCREEN 0 for VGA adapters.
    WIDTH 80, 43
    
    ...
    
        FOR i% = LBOUND(text$) TO UBOUND(text$)
            ' "Reverse video" highlighting.
            IF selected% = i% THEN COLOR 0, 7 ELSE COLOR 7, 0
            PRINT TAB(3); text$(i%); SPACE$(78 - LEN(text$(i%)))
        NEXT i%
    
        ' The screen will turn "white" when the last menu item is selected.
        ' This fixes the issue.
        COLOR 7, 0
    
        SLEEP
    ...
    

    请注意,我为上述所有代码假设了一个带有彩色显示器的 VGA 适配器,它早已被各种其他显示适配器标准所取代,这些标准甚至在智能手表等小型设备上使用。

    您应该能够调整代码以满足您的需求。我将其设计为您可以根据需要简单地添加菜单项。此外,显示代码本身完全包含在 FOR...NEXT 循环中,功能紧随其后,因此您只需更改 FOR...NEXT 循环中的内容即可更改显示方式。

    【讨论】:

      【解决方案2】:

      我在同一条船上,想使用 SCREEN 12 作为带有背景颜色的菜单。根据http://www.qb64.net/wiki/index_title_COLOR/

      屏幕模式 12 和 13 只能在 QB 4.5 中使用前景参数!背景颜色 0 可以使用 OUT 更改。

      我也遇到了这个 SUB:

      SCREEN 12
      
      ColourPrint "Hello", 4, 9
      PRINT
      ColourPrint "bob", 3, 10
      
      
      SUB ColourPrint (t$, fg%, bg%)
          ' t$ = printing text
          ' fg% = foreground colour
          ' bg% = background colour
          DIM h%(1 + 32 * LEN(t$))
          x1% = 8 * (POS(0) - 1)
          y1% = 16 * (CSRLIN - 1)
          x2% = x1% + 8 * LEN(t$) - 1
          y2% = y1% + 15
          LINE (x1%, y1%)-(x2%, y2%), bg%, BF
          GET (x1%, y1%)-(x2%, y2%), h%()
          COLOR fg% XOR bg%
          PRINT t$;
          PUT (x1%, y1%), h%(), XOR
          ERASE h%
      END SUB
      

      这个网站有很多菜单示例可能也会有所帮助:

      http://www.brisray.com/qbasic/qmenu.htm

      【讨论】:

        【解决方案3】:

        基本上你需要一个循环:

        1. 在变量中跟踪当前选择的菜单项(通常是菜单项的索引:1、2、3...) - 我们称之为 SELECTED
        2. 在屏幕上绘制菜单并突出显示所选项目(您需要遍历所有菜单项并在 SELECTED = 当前菜单项索引时突出显示)
        3. 等待按键被按下:
          1. 如果键为 UP,则选择上一个菜单项 (SELECTED = SELECTED - 1)
          2. 如果键为 DOWN,则选择下一个菜单项 (SELECTED = SELECTED + 1)
          3. 如果键是 ENTER 则退出菜单并返回所选项目

        我在这里有一个完整的示例,但它是基于文本的菜单。你可以让它适应你的问题。主要功能在“菜单”功能上:

        DECLARE FUNCTION countItems% (items$)
        DECLARE FUNCTION menu% (row%, col%, items$)
        DECLARE FUNCTION widestItemLength% (items$)
        
        DEFINT A-Z
        
        CONST SEPARATOR = ";"
        
        CLS
        selectedMenuOption = menu(1, 1, "APPLE;BANANA;ORANGE;EXIT")
        
        PRINT
        PRINT
        PRINT "Selected menu option:"; selectedMenuOption
        
        ' Returns how much items we have in the menu
        '
        FUNCTION countItems (items$)
        
        count = 1
        
        DO
            i = INSTR(i + 1, items$, SEPARATOR)
            IF i > 0 THEN count = count + 1
        LOOP UNTIL i = 0
        
        countItems = count
        
        END FUNCTION
        
        ' Main menu functionality
        ' 1. shows the menu highlighting the selected item
        ' 2. wait for a key to be pressed
        '   a. UP -> select previous item
        '   b. DOWN -> select next
        '   c. ENTER -> exit and returns the index of the current selected item
        '
        FUNCTION menu (row%, col%, items$)
        
        widestLength = widestItemLength(items$)
        itemCount = countItems(items$)
        selected = 1    ' menu item index starting by 1
        
        DO
            ' Prints the menu on the screen
            itemEnd = 0
            LOCATE row%, col%
            FOR i = 1 TO itemCount
                itemStart = itemEnd + 1
                itemEnd = INSTR(itemStart, items$, SEPARATOR)
                IF itemEnd = 0 THEN itemEnd = LEN(items$) + 1
                item$ = MID$(items$, itemStart, itemEnd - itemStart)
                item$ = " " + item$ + SPACE$(widestLength - LEN(item$)) + " "
                IF selected = i THEN COLOR 0, 7 ELSE COLOR 7, 0
                LOCATE CSRLIN + 1, col: PRINT item$;
            NEXT
        
            WHILE INKEY$ <> "": WEND            ' Clears the keyboard buffer
            DO: k$ = INKEY$: LOOP WHILE k$ = "" ' Waits for a key to be pressed
        
            SELECT CASE k$
                ' Up key pressed - select previous menu item
                CASE CHR$(0) + "H": IF selected > 1 THEN selected = selected - 1
                ' Down key pressed - select next menu item
                CASE CHR$(0) + "P": IF selected < itemCount THEN selected = selected + 1
            END SELECT
        
        LOOP UNTIL k$ = CHR$(13)    ' Loops until the key pressed is enter
        
        menu = selected ' returns the selected menu item index
        
        COLOR 7, 0
        
        END FUNCTION
        
        ' Returns the size of the widest menu item
        '
        FUNCTION widestItemLength (items$)
        
        widestLen = 0
        itemEnd = 0
        
        DO
            itemStart = itemEnd + 1
            itemEnd = INSTR(itemStart, items$, SEPARATOR)
            IF itemEnd = 0 THEN itemEnd = LEN(items$) + 1
            itemLen = itemEnd - itemStart
            IF itemLen > widestLen THEN widestLen = itemLen
        LOOP UNTIL itemEnd = LEN(items$) + 1
        
        widestItemLength = widestLen
        
        END FUNCTION
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2015-05-13
          • 1970-01-01
          • 2021-08-03
          相关资源
          最近更新 更多