有没有人有示例代码或说明来完成这项工作?我从来没有能够完成使用箭头键和enter选择的突出显示菜单。提前致谢!
我预计通过为每个选项绘制框,并在选择选项时为文本着色时重新绘制颜色框来实现这一点。我只是不确定如何设计一个循环来实现这一点。我对INKEY$
函数和SELECT CASE
语句很满意,但我不知道如何将它们考虑在内。
突出显示的菜单将绘制菜单并等待循环中的按键或使用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
循环内的内容即可更改显示方式。
我在同一条船上,想使用 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
这个网站有一堆菜单示例,可能也有帮助:
基本上你需要一个循环:
我在这里有一个完整的例子,但基于文本的菜单。你可以让它适应你的问题。主要功能在“菜单”功能上:
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