2013-04-15 28 views
9

Tôi tạo ra một ứng dụng giao diện điều khiển trong delphi 7, mà là vụ phải hiển thị thông điệp sau khi bạn nhấn nút enter:Cách tạo ứng dụng bảng điều khiển chờ khóa "Enter", nhưng tự động tiếp tục sau thời gian?

begin 
    writeln ('Press ENTER to continue'); 
    readln; 
    writeln ('blablabla'); 
    writeln ('blablabla'); 
end; 

Cái này là người dùng có thể nhấn nút bất kỳ để tiếp tục và đó là vấn đề. Tôi chỉ muốn chương trình tiếp tục nếu người dùng nhấn nút enter của bàn phím. Ngoại trừ, tôi cần nó để tự động tiếp tục sau một khoảng thời gian, chẳng hạn như 5 giây, mà không có đầu vào của người dùng.

Làm cách nào để tạo ứng dụng bảng điều khiển chờ một khoảng thời gian để người dùng nhấn phím Enter, nhưng tự động tiếp tục nếu người dùng không?

+0

'Readln' dòng chảy khối thực hiện cho đến khi người dùng nhấn RETURN. – OnTheFly

+0

Vâng vâng, đó là mấu chốt của câu hỏi không phải là nó –

+0

Nếu bạn muốn được trợ giúp về mã của mình, hãy đăng ** mã thực **. Đăng nội dung nào đó không có ý nghĩa đối với câu hỏi của bạn sẽ không hữu ích. (Không có "nút" trong ứng dụng giao diện điều khiển, vì vậy tôi đoán bạn có nghĩa là phím '5'.' ReadLn' đợi cho đến khi 'Enter' được nhấn, vì vậy nó sẽ không hoạt động với phím '5' trừ khi bạn bấm '5' và sau đó là 'Enter'. Nhưng nó không rõ ràng những gì bạn đang thực sự yêu cầu ở đây, và mã của bạn không giúp." Hiển thị tin nhắn trên nút 5 "và" Nhấn ENTER để tiếp tục "dường như không khớp Hãy [sửa] câu hỏi của bạn để làm cho nó rõ ràng hơn về những gì bạn đang yêu cầu chúng tôi –

Trả lời

9

Bạn có thể thử mã này (chuyển thể từ đơn vị SynCommons.pas của chúng tôi, trong vòng mORMot của chúng tôi khuôn khổ):

procedure ConsoleWaitForEnterKey(TimeOut: integer); 
    function KeyPressed(ExpectedKey: Word):Boolean; 
    var lpNumberOfEvents: DWORD; 
     lpBuffer: TInputRecord; 
     lpNumberOfEventsRead : DWORD; 
     nStdHandle: THandle; 
    begin 
    result := false; 
    nStdHandle := GetStdHandle(STD_INPUT_HANDLE); 
    lpNumberOfEvents := 0; 
    GetNumberOfConsoleInputEvents(nStdHandle,lpNumberOfEvents); 
    if lpNumberOfEvents<>0 then begin 
     PeekConsoleInput(nStdHandle,lpBuffer,1,lpNumberOfEventsRead); 
     if lpNumberOfEventsRead<>0 then 
     if lpBuffer.EventType=KEY_EVENT then 
      if lpBuffer.Event.KeyEvent.bKeyDown and 
      ((ExpectedKey=0) or (lpBuffer.Event.KeyEvent.wVirtualKeyCode=ExpectedKey)) then 
      result := true else 
      FlushConsoleInputBuffer(nStdHandle) else 
      FlushConsoleInputBuffer(nStdHandle); 
    end; 
    end; 
    var Stop: cardinal; 
begin 
    Stop := GetTickCount+TimeOut*1000; 
    while (not KeyPressed(VK_RETURN)) and (GetTickCount<Stop) do 
    Sleep(50); // check every 50 ms 
end; 

Lưu ý rằng phiên bản nhúng trong mORMot không cho phép gọi phương thức TThread.Synchronize() và cũng xử lý một vòng tin nhắn GDI, nếu cần. Thủ tục này chỉ phù hợp với nhu cầu của bạn, tôi hy vọng.

+0

nó không nhận ra bất kỳ biến nào, thư viện là gì? – user2276109

+5

Sử dụng đơn vị Windows. –

+0

Có, tất nhiên, đặt Windows trong mệnh đề đơn vị của bạn! –

6

Tôi đã làm điều tương tự như sau một vài lần trước đây:

đầu tiên khai báo một vài biến toàn cầu:

var 
    hIn: THandle; 
    hTimer: THandle; 
    threadID: cardinal; 
    TimeoutAt: TDateTime; 
    WaitingForReturn: boolean = false; 
    TimerThreadTerminated: boolean = false; 

Thứ hai, thêm chức năng

function TimerThread(Parameter: pointer): integer; 
var 
    IR: TInputRecord; 
    amt: cardinal; 
begin 
    result := 0; 
    IR.EventType := KEY_EVENT; 
    IR.Event.KeyEvent.bKeyDown := true; 
    IR.Event.KeyEvent.wVirtualKeyCode := VK_RETURN; 
    while not TimerThreadTerminated do 
    begin 
    if WaitingForReturn and (Now >= TimeoutAt) then 
     WriteConsoleInput(hIn, IR, 1, amt); 
    sleep(500); 
    end; 
end; 

procedure StartTimerThread; 
begin 
    hTimer := BeginThread(nil, 0, TimerThread, nil, 0, threadID); 
end; 

procedure EndTimerThread; 
begin 
    TimerThreadTerminated := true; 
    WaitForSingleObject(hTimer, 1000); 
    CloseHandle(hTimer); 
end; 

procedure TimeoutWait(const Time: cardinal); 
var 
    IR: TInputRecord; 
    nEvents: cardinal; 
begin 

    TimeOutAt := IncSecond(Now, Time); 
    WaitingForReturn := true; 

    while ReadConsoleInput(hIn, IR, 1, nEvents) do 
    if (IR.EventType = KEY_EVENT) and 
     (TKeyEventRecord(IR.Event).wVirtualKeyCode = VK_RETURN) 
     and (TKeyEventRecord(IR.Event).bKeyDown) then 
     begin 
     WaitingForReturn := false; 
     break; 
     end; 

end; 

Bây giờ bạn có thể sử dụng TimeoutWait đợi cho Return, nhưng không dài hơn số giây đã cho. Nhưng bạn phải thiết lập hIn và gọi StartTimerThread trước khi bạn sử dụng chức năng này:

begin 

    hIn := GetStdHandle(STD_INPUT_HANDLE); 
    StartTimerThread; 

    Writeln('A'); 
    TimeoutWait(5); 

    Writeln('B'); 
    TimeoutWait(5); 

    Writeln('C'); 
    TimeoutWait(5); 

    EndTimerThread; 

end. 

Bạn có thể thoát khỏi StartTimerThread, đặc biệt là nếu bạn bắt đầu một thread cho mỗi cuộc gọi, nhưng nó có thể là khó khăn hơn để gọi TimeoutWait nhiều lần trong một hàng rồi.

+0

ok cảm ơn điều này là làm việc, tuy nhiên có một số nhà khai thác thiếu mã ur, mà tôi đã phải đặt, nhưng nó làm việc – user2276109

+2

@ user2276109: Tôi không sử dụng các toán tử được định nghĩa tùy chỉnh trong mã của tôi. –

3

Đơn vị điều khiển

unit Console; 

interface 

procedure WaitAnyKeyPressed(const TextMessage: string = ''); overload; inline; 
procedure WaitAnyKeyPressed(TimeDelay: Cardinal; const TextMessage: string = ''); overload; inline; 
procedure WaitForKeyPressed(KeyCode: Word; const TextMessage: string = ''); overload; inline; 
procedure WaitForKeyPressed(KeyCode: Word; TimeDelay: Cardinal; const TextMessage: string = ''); overload; 

implementation 

uses 
    System.SysUtils, WinAPI.Windows; 

procedure WaitAnyKeyPressed(const TextMessage: string); 
begin 
    WaitForKeyPressed(0, 0, TextMessage) 
end; 

procedure WaitAnyKeyPressed(TimeDelay: Cardinal; const TextMessage: string); 
begin 
    WaitForKeyPressed(0, TimeDelay, TextMessage) 
end; 

procedure WaitForKeyPressed(KeyCode: Word; const TextMessage: string); 
begin 
    WaitForKeyPressed(KeyCode, 0, TextMessage) 
end; 

type 
    TTimer = record 
    Started: TLargeInteger; 
    Frequency: Cardinal; 
    end; 

var 
    IsElapsed: function(const Timer: TTimer; Interval: Cardinal): Boolean; 
    StartTimer: procedure(var Timer: TTimer); 

procedure WaitForKeyPressed(KeyCode: Word; TimeDelay: Cardinal; const TextMessage: string); 
var 
    Handle: THandle; 
    Buffer: TInputRecord; 
    Counter: Cardinal; 
    Timer: TTimer; 
begin 
    Handle := GetStdHandle(STD_INPUT_HANDLE); 
    if Handle = 0 then 
    RaiseLastOSError; 
    if not (TextMessage = '') then 
    Write(TextMessage); 
    if not (TimeDelay = 0) then 
    StartTimer(Timer); 
    while True do 
    begin 
     Sleep(0); 
     if not GetNumberOfConsoleInputEvents(Handle, Counter) then 
     RaiseLastOSError; 
     if not (Counter = 0) then 
     begin 
      if not ReadConsoleInput(Handle, Buffer, 1, Counter) then 
      RaiseLastOSError; 
      if (Buffer.EventType = KEY_EVENT) and Buffer.Event.KeyEvent.bKeyDown then 
      if (KeyCode = 0) or (KeyCode = Buffer.Event.KeyEvent.wVirtualKeyCode) then 
       Break 
     end; 
     if not (TimeDelay = 0) and IsElapsed(Timer, TimeDelay) then 
     Break 
    end 
end; 

function HardwareIsElapsed(const Timer: TTimer; Interval: Cardinal): Boolean; 
var 
    Passed: TLargeInteger; 
begin 
    QueryPerformanceCounter(Passed); 
    Result := (Passed - Timer.Started) div Timer.Frequency > Interval 
end; 

procedure HardwareStartTimer(var Timer: TTimer); 
var 
    Frequency: TLargeInteger; 
begin 
    QueryPerformanceCounter(Timer.Started); 
    QueryPerformanceFrequency(Frequency); 
    Timer.Frequency := Frequency div 1000 
end; 

function SoftwareIsElapsed(const Timer: TTimer; Interval: Cardinal): Boolean; 
begin 
    Result := (GetCurrentTime - Cardinal(Timer.Started)) > Interval 
end; 

procedure SoftwareStartTimer(var Timer: TTimer); 
begin 
    PCardinal(@Timer.Started)^ := GetCurrentTime 
end; 

initialization 
    if QueryPerformanceCounter(PLargeInteger(@@IsElapsed)^) and QueryPerformanceFrequency(PLargeInteger(@@IsElapsed)^) then 
    begin 
     StartTimer := HardwareStartTimer; 
     IsElapsed := HardwareIsElapsed 
    end 
    else 
    begin 
     StartTimer := SoftwareStartTimer; 
     IsElapsed := SoftwareIsElapsed 
    end 

end. 

Các thử nghiệm hoặc chương trình mẫu

program Test; 

{$APPTYPE CONSOLE} 
{$R *.res} 

uses 
    WinAPI.Windows, 
    Console in 'Console.pas'; 

begin 
    Console.WaitAnyKeyPressed('Press any key to continue ...'); 
    WriteLn; 
    Console.WaitAnyKeyPressed(5000, 'I''ll wait 5 seconds until You press any key to continue ...'); 
    WriteLn; 
    Console.WaitForKeyPressed(VK_SPACE, 'Press [Space] key to continue ...'); 
    WriteLn; 
    Console.WaitForKeyPressed(VK_ESCAPE, 5000, 'I''ll wait 5 seconds until You press [Esc] key to continue ...'); 
    WriteLn 
end. 
+0

Cảm ơn bạn đã đăng đơn vị bảng điều khiển này! Nó sẽ hữu ích. Nó được sao chép từ một đơn vị lớn hơn hay thư viện? – Shannon