Làm thế nào để tôi đảm bảo một đoạn mã chỉ chạy một lần?


18

Tôi có một số mã mà tôi chỉ muốn chạy một lần, mặc dù các trường hợp kích hoạt mã đó có thể xảy ra nhiều lần.

Ví dụ: khi người dùng nhấp chuột, tôi muốn nhấp vào điều:

void Update() {
    if(mousebuttonpressed) {
        ClickTheThing(); // I only want this to happen on the first click,
                         // then never again.
    }
}

Tuy nhiên, với mã này, mỗi lần tôi nhấp chuột, mọi thứ sẽ được nhấp. Làm thế nào tôi có thể làm cho nó xảy ra chỉ một lần?


7
Tôi thực sự thấy điều này thật buồn cười vì tôi không nghĩ nó nằm trong "các vấn đề lập trình dành riêng cho trò chơi". Nhưng tôi không bao giờ thực sự thích quy tắc đó.
ClassicThunder

3
@ClassicThunder Yep, chắc chắn là nhiều hơn về mặt lập trình chung của mọi thứ. Bỏ phiếu để đóng nếu bạn thích, tôi đã đăng câu hỏi nhiều hơn để chúng tôi có điều gì đó để chỉ cho mọi người khi họ đặt câu hỏi tương tự như vậy. Nó có thể được mở hoặc đóng cho mục đích đó.
MichaelHouse

Câu trả lời:


41

Sử dụng cờ boolean.

Trong ví dụ hiển thị, bạn sẽ sửa đổi mã thành như sau:

//a boolean flag that lets us "remember" if this thing has happened already
bool thatThingHappened = false;

void Update() {
    if(!thatThingHappened && mousebuttonpressed) {
        //if that thing hasn't happened yet and the mouse is pressed
        thatThingHappened = true;
        ClickTheThing();
    }
}

Hơn nữa, nếu bạn muốn có thể lặp lại hành động, nhưng giới hạn tần suất của hành động (tức là thời gian tối thiểu giữa mỗi hành động). Bạn sẽ sử dụng một cách tiếp cận tương tự, nhưng đặt lại cờ sau một khoảng thời gian nhất định. Xem câu trả lời của tôi ở đây để biết thêm ý tưởng về điều đó.


1
Câu trả lời rõ ràng cho câu hỏi của bạn :-) Tôi rất muốn xem các phương pháp thay thế nếu bạn hoặc bất kỳ ai khác biết về bất kỳ. Việc sử dụng Boolean toàn cầu cho việc này luôn có mùi với tôi.
Evorlor

1
@Evorlor Không rõ ràng với mọi người :). Tôi cũng quan tâm đến các giải pháp thay thế, có lẽ chúng ta có thể học được điều gì đó không quá rõ ràng!
MichaelHouse

2
@Evorlor thay thế, bạn có thể sử dụng các đại biểu (con trỏ hàm) và thay đổi hành động được thực hiện. ví dụ onStart() { delegate = doSomething; } ... if(mousebuttonpressed) { delegate.Execute(); }void doSomething() { doStuff(); delegate = funcDoNothing; }nhưng cuối cùng tất cả các tùy chọn kết thúc có một lá cờ của một số loại bạn thiết lập / unset ... và đại biểu trong trường hợp này là không có gì khác (trừ khi bạn có nhiều hơn hai lựa chọn những việc cần làm có lẽ?).
wonderra

2
@wondra Vâng, đó là một cách. Thêm nó Chúng tôi cũng có thể lập một danh sách các giải pháp có thể cho câu hỏi này.
MichaelHouse

1
@JamesSnell Nhiều khả năng nếu nó đa luồng. Nhưng vẫn là một thực hành tốt.
MichaelHouse

21

Nếu cờ bool không đủ hoặc bạn muốn cải thiện khả năng đọc * của mã trong void Update()phương thức, bạn có thể xem xét sử dụng các đại biểu (con trỏ hàm):

public class InputController 
{
  //declare delegate type:
  //<accessbility> delegate <return type> <name> ( <parameter1>, <paramteter2>, ...)
  public delegate void ClickAction();

  //declare a variable of that type
  public ClickAction ClickTheThing { get; set; }

  void onStart()
  {
    //assign it the method you wish to execute on first click
    ClickTheThing = doStuff;
  }

  void Update() {
    if(mousebuttonpressed) {
        //you simply call the delegate here, the currently assigned function will be executed
        ClickTheThing();
     }
  }

  private void doStuff()
  {
    //some logic here
    ClickTheThing = doNothing; //and set the delegate to other(empty) funtion
  }

  //or do something else
  private void doNothing(){}
}

Đối với các đại biểu "thực hiện một lần" đơn giản là quá mức cần thiết, vì vậy tôi sẽ đề nghị sử dụng cờ bool thay thế.
Tuy nhiên, nếu bạn cần chức năng phức tạp hơn, các đại biểu có lẽ là sự lựa chọn tốt hơn. Ví dụ: nếu bạn muốn chuỗi thực hiện nhiều hành động khác nhau: một lần nhấp đầu tiên, lần khác vào lần thứ hai và một lần nữa vào lần thứ ba, bạn có thể thực hiện:

func1() 
{
  //do logic 1 here
  someDelegate = func2;
}

func2() 
{
  //do logic 2 here
  someDelegate = func3;
}
//etc...

thay vì làm hỏng mã của bạn với hàng chục cờ khác nhau.
* với chi phí bảo trì thấp hơn của phần còn lại của mã


Tôi đã làm một số hồ sơ với kết quả khá nhiều như tôi mong đợi:

----------------------------------------
|     Method     |  Unity   |    C++   |
| -------------------------------------|
| positive flag  |  21 ms   |   6 ms   |
| negative flag  |  5 ms    |   7 ms   |
| delegate       |  25 ms   |   14 ms  |
----------------------------------------

Thử nghiệm đầu tiên được chạy trên Unity 5.1.2, được đo bằng System.Diagnostics.Stopwatchdự án được xây dựng 32 bit (không phải trong thiết kế!). Một cái khác trên Visual Studio 2015 (v140) được biên dịch ở chế độ phát hành 32 bit với cờ / Ox. Cả hai thử nghiệm đều được chạy trên CPU Intel i5-4670K @ 3,4GHz, với 10.000.000 lần lặp cho mỗi lần thực hiện. mã:

//positive flag
if(flag){
    doClick();
    flag = false;
}
//negative flag
if(!flag){ }
else {
    doClick();
    flag = false;
}
//delegate
action();

kết luận: Mặc dù trình biên dịch Unity thực hiện công việc tốt khi tối ưu hóa các lệnh gọi hàm, mang lại kết quả gần như tương tự cho cả cờ dương và đại biểu (tương ứng 21 và 25 ms), việc gọi sai nhánh hoặc gọi hàm vẫn khá tốn kém (lưu ý: đại biểu nên được giả sử bộ đệm trong bài kiểm tra này).
Thật thú vị, trình biên dịch Unity không đủ thông minh để tối ưu hóa chi nhánh khi có 99 triệu lỗi sai liên tiếp, do đó, việc phủ định thủ công thử nghiệm sẽ mang lại một số hiệu suất tăng cho kết quả tốt nhất là 5 ms. Phiên bản C ++ không hiển thị bất kỳ tăng hiệu suất nào cho điều kiện phủ định, tuy nhiên tổng chi phí chung của chức năng gọi thấp hơn đáng kể.
quan trọng nhất: sự khác biệt là khá nhiều không liên quan cho bất kỳ kịch bản trong thế giới thực


4
AFAIK điều này cũng tốt hơn từ quan điểm hiệu suất, quá. Gọi một hàm no-op, giả sử rằng hàm đó đã có trong bộ đệm hướng dẫn, nhanh hơn rất nhiều so với kiểm tra cờ, đặc biệt là khi kiểm tra đó được lồng trong các điều kiện khác .
Kỹ sư

2
Tôi nghĩ Navin đã đúng, tôi có khả năng có hiệu suất kém hơn so với việc kiểm tra cờ boolean - trừ khi JIT của bạn thực sự thông minh và thay thế toàn bộ chức năng bằng nghĩa đen. Nhưng trừ khi chúng tôi hồ sơ kết quả, chúng tôi không thể biết chắc chắn.
wonderra

2
Hmm, câu trả lời này làm tôi nhớ đến sự tiến hóa của một kỹ sư SW . Đùa sang một bên, nếu bạn thực sự cần (và chắc chắn) về việc tăng hiệu suất này, hãy thực hiện nó. Nếu không, tôi đề nghị giữ nó HÔN và sử dụng cờ boolean, như đề xuất trong câu trả lời khác . Tuy nhiên, +1 cho giải pháp thay thế được trình bày ở đây!
mucaho

1
Tránh các điều kiện khi có thể. Tôi đang nói về những gì xảy ra ở cấp độ máy, cho dù đó là mã riêng của bạn, trình biên dịch JIT hay trình thông dịch. Lượt truy cập bộ đệm L1 tương đương với lần truy cập đăng ký, có thể chậm hơn một chút, tức là 1 hoặc 2 chu kỳ, trong khi đó, việc phân nhánh sai, xảy ra ít thường xuyên hơn nhưng vẫn trung bình quá nhiều, chi phí theo thứ tự 10-20 chu kỳ. Xem câu trả lời của Jalf: stackoverflow.com/questions/289405/, Và này: stackoverflow.com/questions/11227809/iêu
Kỹ sư

1
Ngoài ra, hãy nhớ rằng các điều kiện trong câu trả lời của Byte56 phải được gọi là mỗi bản cập nhật duy nhất trong suốt thời gian của chương trình của bạn và cũng có thể được lồng hoặc có các điều kiện lồng nhau trong chúng, làm cho vấn đề trở nên tồi tệ hơn. Con trỏ chức năng / Đại biểu là cách để đi.
Kỹ sư

3

Để hoàn thiện

(Không thực sự khuyên bạn nên làm điều này vì nó thực sự khá đơn giản để chỉ viết một cái gì đó như thế if(!already_called), nhưng nó sẽ là "chính xác" để làm điều đó.)

Không có gì đáng ngạc nhiên, tiêu chuẩn C ++ 11 đã giải thích vấn đề khá tầm thường khi gọi một hàm và làm cho nó trở nên siêu rõ ràng:

#include <mutex>

void Update() {
if(mousebuttonpressed) {
    static std::once_flag f;
    std::call_once(f, ClickTheThing);
}

}

Phải thừa nhận rằng, giải pháp tiêu chuẩn có phần vượt trội so với giải pháp tầm thường khi có chủ đề vì nó vẫn đảm bảo luôn luôn chính xác một cuộc gọi xảy ra, không bao giờ có gì khác.

Tuy nhiên, thông thường bạn không chạy một vòng lặp sự kiện đa luồng và nhấn các nút của nhiều con chuột cùng một lúc, do đó sự an toàn của luồng là hơi thừa đối với trường hợp của bạn.

Về mặt thực tế, điều đó có nghĩa là ngoài việc khởi tạo an toàn luồng của boolean cục bộ (mà C ++ 11 vẫn đảm bảo an toàn cho luồng), phiên bản tiêu chuẩn cũng phải thực hiện thao tác test_set nguyên tử trước khi gọi hoặc không gọi chức năng.

Tuy nhiên, nếu bạn thích rõ ràng, có giải pháp.

EDIT:
Hừ. Bây giờ tôi đã ngồi ở đây, nhìn chằm chằm vào mã đó trong vài phút, tôi gần như có xu hướng giới thiệu nó.
Trên thực tế, nó gần như không ngớ ngẩn như lúc đầu, thực sự nó truyền đạt rất rõ ràng và rõ ràng ý định của bạn ... được cho là có cấu trúc tốt hơn và dễ đọc hơn bất kỳ giải pháp nào khác liên quan đến một ifhoặc như vậy.


2

Một số đề xuất sẽ thay đổi tùy thuộc vào kiến ​​trúc.

Tạo click ThisThing () dưới dạng con trỏ hàm / biến thể / DLL / so / etc ... và đảm bảo rằng nó được khởi tạo cho hàm yêu cầu của bạn khi đối tượng / thành phần / mô-đun / vv ... được khởi tạo.

Trong trình xử lý bất cứ khi nào nhấn nút chuột, sau đó gọi con trỏ hàm click ThisThing () và sau đó thay thế ngay con trỏ bằng một con trỏ hàm NOP (không hoạt động) khác.

Không cần cờ và logic bổ sung để ai đó làm hỏng sau này, chỉ cần gọi nó và thay thế nó mỗi lần và vì đó là NOP, NOP không làm gì cả và được thay thế bằng NOP.

Hoặc bạn có thể sử dụng cờ và logic để bỏ qua cuộc gọi.

Hoặc bạn có thể ngắt kết nối chức năng Update () sau cuộc gọi để thế giới bên ngoài quên nó và không bao giờ gọi lại.

Hoặc bạn có chính click ThisThing () sử dụng một trong những khái niệm này để chỉ trả lời với công việc hữu ích một lần. Bằng cách này, bạn có thể sử dụng một đối tượng / thành phần / mô-đun cơ bản click ThisT BreathOnce () và khởi tạo nó bất cứ nơi nào bạn cần hành vi này và không ai trong số các trình cập nhật của bạn cần logic đặc biệt ở mọi nơi.


2

Sử dụng con trỏ hàm hoặc đại biểu.

Biến giữ con trỏ hàm không cần phải được kiểm tra rõ ràng cho đến khi cần thay đổi. Và khi bạn không còn cần phải nói logic để chạy, hãy thay thế bằng một tham chiếu đến một chức năng trống / không hoạt động. So sánh với việc thực hiện các điều kiện kiểm tra mọi khung hình trong toàn bộ vòng đời của chương trình của bạn - ngay cả khi cờ đó chỉ cần trong một vài khung hình đầu tiên sau khi khởi động! - Ô uế và không hiệu quả. (Quan điểm của Boreal về dự đoán tuy nhiên được thừa nhận về vấn đề này.)

Các điều kiện lồng nhau, mà những điều này thường tạo thành, thậm chí còn tốn kém hơn so với việc phải kiểm tra một điều kiện duy nhất cho mỗi khung, vì dự đoán nhánh không còn có thể thực hiện phép thuật của nó trong trường hợp đó. Điều đó có nghĩa là sự chậm trễ thường xuyên theo thứ tự 10 giây của chu kỳ - gian hàng tuyệt vời . Việc lồng có thể xảy ra ở trên hoặc dưới cờ boolean này. Tôi hầu như không cần nhắc nhở độc giả về cách các vòng lặp trò chơi phức tạp có thể nhanh chóng trở thành.

Con trỏ hàm tồn tại vì lý do này - sử dụng chúng!


1
Chúng tôi đang suy nghĩ theo cùng một dòng. Cách hiệu quả nhất là ngắt kết nối điều Cập nhật () khỏi bất cứ ai gọi nó không ngừng nghỉ sau khi hoàn thành công việc, điều này rất phổ biến trong các thiết lập tín hiệu kiểu Qt + khe cắm. OP đã không chỉ định môi trường thời gian chạy vì vậy chúng tôi gặp khó khăn khi nói đến tối ưu hóa cụ thể.
Patrick Hughes

1

Trong một số ngôn ngữ script như javascript hoặc lua có thể dễ dàng thực hiện kiểm tra tham chiếu hàm. Trong Lua ( love2d ):

function ClickTheThing()
      .......
end
....

local ctt = ClickTheThing  --I make a local reference to function

.....

function update(dt)
..
    if ctt then
      ctt()
      ctt=nil
    end
..
end

0

Trong máy tính Kiến trúc Von Neumann , bộ nhớ là nơi lưu trữ các hướng dẫn và dữ liệu của chương trình của bạn. Nếu bạn muốn tạo mã chỉ chạy một lần, bạn có thể có mã trong phương thức ghi đè phương thức bằng NOP sau khi phương thức hoàn tất. Bằng cách này, nếu phương thức được chạy lại, sẽ không có gì xảy ra.


6
Điều này sẽ phá vỡ một vài kiến ​​trúc ghi bảo vệ bộ nhớ chương trình hoặc chạy từ ROM. Nó cũng có thể sẽ đặt ra các cảnh báo chống vi-rút ngẫu nhiên, tùy thuộc vào những gì được cài đặt.
Patrick Hughes

0

Trong python nếu kế hoạch của bạn là một kẻ ngốc với người khác trong dự án:

code = compile('main code'+'del code', '<string>', 'exec')
exec code

kịch bản này chứng thực mã:

from time import time as t

code = compile('del code', '<string>', 'exec')

print 'see code object:'
print code

while True:
    try:
        user = compile(raw_input('play with it (variable name is code) (type done to be done:\t'), '<user_input>', 'exec')
        exec user
    except BaseException as e:
        print e
        break

exec code

print 'no more code object:'
try:
    print code
except BaseException as e:
    print e

while True:
    try:
        user = compile(raw_input('try to play with it again (type done to be done:\t'), '<user_input>', 'exec')
        exec user
    except BaseException as e:
        print e
        break

0

Đây là một đóng góp khác, đó là một chút chung chung / có thể tái sử dụng, dễ đọc hơn một chút và có thể bảo trì, nhưng có thể kém hiệu quả hơn các giải pháp khác.

Hãy gói gọn logic thực hiện một lần của chúng ta trong một lớp, Một lần:

class Once
{
    private Action body;
    public bool HasBeenCalled { get; private set; }
    public Once(Action body)
    {
        this.body = body;
    }
    public void Call()
    {
        if (!HasBeenCalled)
        {
            body();
        }
        HasBeenCalled = true;
    }
    public void Reset() { HasBeenCalled = false; }
}

Sử dụng nó giống như ví dụ được cung cấp trông như sau:

Once clickTheThingOnce = new Once(ClickTheThing);

void Update() {
    if(mousebuttonpressed) {
        clickTheThingOnce.Call(); // ClickTheThing is only called once
                                  // or until .Reset() is called
    }
}

0

Bạn có thể xem xét sử dụng một biến tĩnh.

void doOnce()
{
   static bool executed = false;

   if(executed == false)
   {
      ...Your code here
      executed = true;
   }
}

Bạn có thể thực hiện điều này trong ClickTheThing()chính chức năng hoặc tạo một chức năng khác và gọi ClickTheThing()trong phần thân.

Nó tương tự như ý tưởng sử dụng một cờ như được đề xuất trong các giải pháp khác, nhưng cờ được bảo vệ khỏi mã khác và không thể bị thay đổi ở nơi khác do là cục bộ của hàm.


1
... nhưng điều này ngăn bạn chạy mã một lần 'cho mỗi đối tượng'. (Nếu đó là những gì người dùng cần ..;))
Vaillancourt

0

Tôi thực sự đã gặp phải vấn đề nan giải này với Đầu vào bộ điều khiển Xbox. Mặc dù không chính xác giống nhau nhưng nó khá giống nhau. Bạn có thể thay đổi mã trong ví dụ của tôi để phù hợp với nhu cầu của bạn.

Chỉnh sửa: Tình huống của bạn sẽ sử dụng điều này ->

https://docs.microsoft.com/en-us/windows/desktop/api/winuser/ns-winuser-tagrawmouse

Và bạn có thể tìm hiểu cách tạo một lớp đầu vào thô thông qua ->

https://docs.microsoft.com/en-us/windows/desktop/inputdev/raw-input

Nhưng .. bây giờ vào thuật toán siêu tuyệt vời ... không thực sự, nhưng hey .. nó khá tuyệt :)

* Vì vậy, ... chúng ta có thể lưu trữ trạng thái của mọi nút và được nhấn, phát hành và giữ xuống !!! Chúng tôi cũng có thể kiểm tra Thời gian giữ, nhưng điều đó yêu cầu một câu lệnh if duy nhất và có thể kiểm tra bất kỳ số lượng nút nào, nhưng có một số quy tắc xem bên dưới để biết thông tin này.

Rõ ràng nếu chúng tôi muốn kiểm tra xem có thứ gì được nhấn, phát hành hay không, v.v. bạn sẽ làm "Nếu (Cái này) {}", nhưng điều này cho thấy cách chúng tôi có thể lấy trạng thái báo chí và sau đó tắt khung hình tiếp theo để " ismousepressed "sẽ thực sự sai trong lần kiểm tra tiếp theo.

Mã đầy đủ ở đây: https://github.com/JeremyDX/DX_B/blob/master/DX_B/XGameInput.cpp

Làm thế nào nó hoạt động..

Vì vậy, tôi không chắc chắn các giá trị bạn nhận được khi bạn mô tả nếu nhấn nút hay không, nhưng về cơ bản khi tôi tải trong XInput, tôi nhận được giá trị 16 bit trong khoảng từ 0 đến 65535, điều này có 15 bit trạng thái có thể cho "Đã nhấn".

Vấn đề là mỗi khi tôi kiểm tra điều này Nó sẽ chỉ cho tôi trạng thái hiện tại của thông tin. Tôi cần một cách để chuyển đổi trạng thái hiện tại thành các giá trị bị ép, phát hành và giữ.

Vì vậy, những gì tôi đã làm là sau đây.

Đầu tiên chúng ta tạo một biến "HIỆN TẠI". Mỗi lần kiểm tra dữ liệu này, chúng tôi đặt "HIỆN TẠI" thành biến "TRƯỚC" và sau đó lưu trữ dữ liệu mới thành "Hiện tại" như được thấy ở đây ->

uint64_t LAST = CURRENT;
CURRENT = gamepad.wButtons;

Với thông tin này, đây là nơi thú vị !!

Bây giờ chúng ta có thể tìm ra nếu một Nút đang được H HEL TRỢ XUỐNG!

BUTTONS_HOLD = LAST & CURRENT;

Những gì nó làm về cơ bản là so sánh hai giá trị và bất kỳ lần nhấn nút nào được hiển thị trong cả hai sẽ giữ nguyên 1 và mọi thứ khác được đặt thành 0.

Tức là (1 | 2 | 4) & (2 | 4 | 8) sẽ mang lại (2 | 4).

Bây giờ chúng ta có các nút "H HEL TRỢ" xuống. Chúng ta có thể nhận phần còn lại.

Nhấn là đơn giản .. chúng tôi lấy trạng thái "HIỆN TẠI" và loại bỏ bất kỳ nút nhấn nào.

BUTTONS_PRESSED = CURRENT ^ BUTTONS_HOLD;

Thay vào đó, chúng tôi chỉ so sánh nó với trạng thái LAST của chúng tôi.

BUTTONS_RELEASED = LAST ^ BUTTONS_HOLD;

Vì vậy, nhìn vào tình hình Pressed. Nếu chúng ta nói Hiện tại chúng ta đã có 2 | 4 | 8 ép. Chúng tôi thấy rằng 2 | 4 nơi tổ chức. Khi chúng ta loại bỏ Held Bits, chúng ta chỉ còn lại 8. Đây là bit mới được nhấn cho chu trình này.

Điều tương tự có thể được áp dụng cho Phát hành. Trong kịch bản này, "LAST" đã được đặt thành 1 | 2 | 4. Vì vậy, khi chúng tôi loại bỏ 2 | 4 bit. Chúng tôi chỉ còn lại 1. Vì vậy, nút 1 đã được phát hành kể từ khung cuối cùng.

Kịch bản trên có lẽ là tình huống lý tưởng nhất mà bạn có thể đưa ra để so sánh bit và nó cung cấp 3 cấp độ dữ liệu mà không có câu lệnh if hoặc cho các vòng lặp chỉ bằng 3 phép tính bit nhanh.

Tôi cũng muốn ghi lại dữ liệu giữ vì vậy mặc dù tình huống của tôi không hoàn hảo ... về cơ bản, chúng tôi sẽ thiết lập các khoản giữ mà chúng tôi muốn kiểm tra.

Vì vậy, mỗi khi chúng tôi đặt dữ liệu Báo chí / Phát hành / Giữ, chúng tôi sẽ kiểm tra xem dữ liệu giữ có bằng với kiểm tra bit giữ hiện tại không. Nếu không, chúng tôi sẽ đặt lại thời gian hiện tại. Trong trường hợp của tôi, tôi đang đặt nó thành các chỉ mục khung để tôi biết nó được giữ bao nhiêu khung.

Nhược điểm của phương pháp này là tôi không thể có thời gian giữ riêng lẻ, nhưng bạn có thể kiểm tra nhiều bit cùng một lúc. Tức là nếu tôi đặt bit giữ thành 1 | 16 nếu 1 hoặc 16 không được giữ thì điều này sẽ thất bại. Vì vậy, nó yêu cầu TẤT CẢ các nút đó được giữ để tiếp tục đánh dấu.

Sau đó, nếu bạn nhìn vào mã, bạn sẽ thấy tất cả các lệnh gọi hàm gọn gàng.

Vì vậy, ví dụ của bạn sẽ được giảm xuống chỉ đơn giản là kiểm tra xem có xảy ra nhấn nút hay không và chỉ nhấn nút một lần với thuật toán này. Ở lần kiểm tra tiếp theo, nhấn nó sẽ không tồn tại vì bạn không thể nhấn nhiều hơn sau đó một khi bạn phải phát hành trước khi bạn có thể nhấn lại.


Vì vậy, về cơ bản bạn sử dụng một bitfield thay vì một bool như đã nêu trong các câu trả lời khác?
Vaillancourt

Vâng khá nhiều lol ..
Jeremy Trifilo

Nó có thể được sử dụng cho các yêu cầu của anh ấy mặc dù với cấu trúc msd dưới đây, "usButtonFlags" chứa một giá trị duy nhất của tất cả các trạng thái nút. docs.microsoft.com/en-us/windows/desktop/api/winuser/ Khăn
Jeremy Trifilo

Mặc dù vậy, tôi không chắc sự cần thiết phải nói tất cả những điều này về các nút điều khiển đến từ đâu. Nội dung cốt lõi của câu trả lời được ẩn giấu bên dưới rất nhiều văn bản gây mất tập trung.
Vaillancourt

Vâng, tôi chỉ đưa ra một kịch bản cá nhân liên quan và những gì tôi đã làm để hoàn thành nó. Mặc dù vậy, tôi sẽ dọn sạch nó sau và chắc chắn tôi sẽ thêm đầu vào Bàn phím và Chuột và đưa ra cách tiếp cận.
Jeremy Trifilo

-3

Lối thoát ngu ngốc nhưng bạn có thể sử dụng vòng lặp for

for (int i = 0; i < 1; i++)
{
    //code here
}

Mã trong vòng lặp sẽ luôn được thực thi khi vòng lặp được chạy. Không có gì trong đó ngăn cản mã được thực thi một lần. Vòng lặp hoặc không vòng lặp cho kết quả chính xác như nhau.
Vaillancourt
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.