2

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

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

4

3 回答 3

2

突出显示的菜单将绘制菜单并等待循环中的按键或使用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循环内的内容即可更改显示方式。

于 2016-06-24T05:01:56.007 回答
1

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

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

我也遇到了这个(还没有测试过):

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

在此处输入图像描述

在此处输入图像描述

在此处输入图像描述

于 2021-10-15T02:56:08.020 回答
0

基本上你需要一个循环:

  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
于 2021-11-30T17:08:40.250 回答