【发布时间】:2022-05-03 20:34:56
【问题描述】:
有没有人有示例代码或说明来完成这项工作?我只是无法完成使用箭头键和 enter 进行选择的突出显示菜单。提前致谢!
我希望通过为每个选项绘制框,并在选择选项时为文本着色的同时用颜色重新绘制框来实现这一点。我只是不确定如何设计一个循环来实现这一点。我对INKEY$ 函数和SELECT CASE 语句很满意,但我不知道如何考虑它们。
【问题讨论】:
标签: loops menu highlight qbasic
有没有人有示例代码或说明来完成这项工作?我只是无法完成使用箭头键和 enter 进行选择的突出显示菜单。提前致谢!
我希望通过为每个选项绘制框,并在选择选项时为文本着色的同时用颜色重新绘制框来实现这一点。我只是不确定如何设计一个循环来实现这一点。我对INKEY$ 函数和SELECT CASE 语句很满意,但我不知道如何考虑它们。
【问题讨论】:
标签: loops menu highlight qbasic
突出显示的菜单将绘制菜单并等待循环中的按键或使用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 中使用前景参数!背景颜色 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
这个网站有很多菜单示例可能也会有所帮助:
【讨论】:
基本上你需要一个循环:
我在这里有一个完整的示例,但它是基于文本的菜单。你可以让它适应你的问题。主要功能在“菜单”功能上:
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
【讨论】: