Jak czekać na naciśnięcie klawisza w R?

139

Chcę wstrzymać mój skrypt R, dopóki użytkownik nie naciśnie klawisza.

Jak mam to zrobic?

Contango
źródło
Czy znalazłeś odpowiedź, którą możesz zaakceptować?
Léo Léopold Hertz 준영

Odpowiedzi:

127

Jak ktoś już napisał w komentarzu, nie musisz wcześniej używać kota readline(). Po prostu napisz:

readline(prompt="Press [enter] to continue")

Jeśli nie chcesz, aby przypisać ją do zmiennej i nie chcą powrotu drukowany w konsoli, zawinąć readline()w sposób invisible():

invisible(readline(prompt="Press [enter] to continue"))
nnn
źródło
Myślę, że to najlepsza odpowiedź.
Léo Léopold Hertz 준영
1
co powiesz na dodanie do niego jeszcze jednej funkcji? press esc keep to exit loop?
I_m_LeMarque
4
@nnn to nie działa, jeśli uruchomię skrypt w rstudio, np. print ("hi") readline ("Naciśnij klawisz, aby kontynuować") print ("ho") Prawdopodobnie dlatego, że sesja nie jest interaktywna. Jak to zrobić w sesji nieinteraktywnej?
PascalIv
79

Metoda 1

Czeka, aż naciśniesz [enter] w konsoli:

cat ("Press [enter] to continue")
line <- readline()

Zawijanie do funkcji:

readkey <- function()
{
    cat ("Press [enter] to continue")
    line <- readline()
}

Ta funkcja jest najlepszym odpowiednikiem Console.ReadKey()w C #.

Metoda 2

Zrób pauzę, aż naciśniesz klawisz [enter] na klawiaturze. Wadą tej metody jest to, że jeśli wpiszesz coś, co nie jest liczbą, wyświetli się błąd.

print ("Press [enter] to continue")
number <- scan(n=1)

Zawijanie do funkcji:

readkey <- function()
{
    cat("[press [enter] to continue]")
    number <- scan(n=1)
}

Metoda 3

Wyobraź sobie, że chcesz poczekać na naciśnięcie klawisza przed wykreśleniem kolejnego punktu na wykresie. W tym przypadku możemy użyć getGraphicsEvent (), aby poczekać na naciśnięcie klawisza w grafie.

Ten przykładowy program ilustruje koncepcję:

readkeygraph <- function(prompt)
{
    getGraphicsEvent(prompt = prompt, 
                 onMouseDown = NULL, onMouseMove = NULL,
                 onMouseUp = NULL, onKeybd = onKeybd,
                 consolePrompt = "[click on graph then follow top prompt to continue]")
    Sys.sleep(0.01)
    return(keyPressed)
}

onKeybd <- function(key)
{
    keyPressed <<- key
}

xaxis=c(1:10) # Set up the x-axis.
yaxis=runif(10,min=0,max=1) # Set up the y-axis.
plot(xaxis,yaxis)

for (i in xaxis)
{
    # On each keypress, color the points on the graph in red, one by one.
    points(i,yaxis[i],col="red", pch=19)
    keyPressed = readkeygraph("[press any key to continue]")
}

Tutaj możesz zobaczyć wykres, z kolorową połową punktów, czekający na kolejne naciśnięcie klawisza na klawiaturze.

Zgodność: Testowane w środowiskach używaj win.graph lub X11 . Działa z Windows 7 x64 z Revolution R v6.1. Nie działa pod RStudio (ponieważ nie używa win.graph).

wprowadź opis obrazu tutaj

Gravitas
źródło
6
Metodę 1 można skrócić, używając promptargumentu do readline. Metoda 2 działałaby z dowolnymi what=""danymi wejściowymi (nie tylko liczbami), gdyby zostały dodane do wywołania scan. getGraphicsEventdziała tylko na określonych urządzeniach graficznych na niektórych platformach (ale jeśli używasz jednego z tych urządzeń, działa dobrze).
Greg Snow,
2
Jeśli używasz tej funkcji (Metoda 1) w pętli i chcesz zatrzymać pętlę, na przykład:if(line == "Q") stop()
Dorian Grv
18

Oto mała funkcja (wykorzystująca pakiet tcltk), która otworzy małe okno i zaczeka, aż klikniesz przycisk Kontynuuj lub naciśniesz dowolny klawisz (podczas gdy małe okno nadal ma fokus), a następnie umożliwi kontynuowanie skryptu.

library(tcltk)

mywait <- function() {
    tt <- tktoplevel()
    tkpack( tkbutton(tt, text='Continue', command=function()tkdestroy(tt)),
        side='bottom')
    tkbind(tt,'<Key>', function()tkdestroy(tt) )

    tkwait.window(tt)
}

Po prostu umieść mywait()skrypt w dowolnym miejscu, w którym chcesz go zatrzymać.

Działa to na każdej platformie obsługującej tcltk (które, jak sądzę, są wszystkie popularne), będzie reagować na każde naciśnięcie klawisza (nie tylko enter), a nawet działa, gdy skrypt jest uruchamiany w trybie wsadowym (ale nadal zatrzymuje się w trybie wsadowym , więc jeśli nie ma Cię tam, aby kontynuować, będzie czekać wiecznie). Można dodać licznik czasu, aby kontynuować działanie po określonym czasie, jeśli nie zostanie kliknięty lub naciśnięty został klawisz.

Nie zwraca informacji, który klawisz został naciśnięty (ale można go w tym celu zmodyfikować).

Greg Snow
źródło
To jest zajebiste. Ale tylko ostrzeżenie, z jakiegoś powodu nie będzie działać na kliencie RStudio-Server ( Error in structure(.External(.C_dotTclObjv, objv), class = "tclObj") : [tcl] invalid command name "toplevel". )
milia
2
@milia, zgadza się. Kod oparty na tcltk musi działać na komputerze lokalnym i nie będzie działać na serwerze RStudio-Server.
Greg Snow
14

R i Rscript wysyłają ''do readline i skanują w trybie nieinteraktywnym (zobacz ? readline). Rozwiązaniem jest wymuszenie stdinużycia skanowania.

cat('Solution to everything? > ')
b <- scan("stdin", character(), n=1)

Przykład:

$ Rscript t.R 
Solution to everything? > 42
Read 1 item
Simon A. Eugster
źródło
2
Niesamowite! To prawie rozwiązuje mój problem . Mimo wszystko byłoby miło, gdyby konsola nie czekała na tekst + Return, a raczej reagowała na pierwsze naciśnięcie klawisza (np. „Naciśnij dowolny klawisz, aby kontynuować”).
Vorac
3

Ta odpowiedź jest podobna do odpowiedzi Simona , ale nie wymaga dodatkowego wejścia poza nową linią.

cat("Press Enter to continue...")
invisible(scan("stdin", character(), nlines = 1, quiet = TRUE))

Używając nlines=1zamiast tego n=1, użytkownik może po prostu nacisnąć klawisz Enter, aby kontynuować skrypt RScript.

Dennis YL
źródło
+1 to jedyna odpowiedź, która faktycznie działa zgodnie z oczekiwaniami. Wewnątrz Rscript: zatrzymuje się i wymaga tylko trafienia, Enteraby kontynuować.
arielf
2
to zepsuło R i musiałem przerwać sesję
blobbymatt
1
w trybie interaktywnym powoduje to przerwanie R i wymaga zakończenia sesji. Dodaj ostrzeżenie do swojego wpisu, w takim przypadku usunę głos przeciw.
HoneyBuddha
Działał dla mnie zgodnie z oczekiwaniami w systemie Windows !. Zaakceptowane rozwiązanie (powyżej) zostało pominięte i nie zostało wstrzymane. Ten faktycznie zatrzymał się i czekał, aż wbiję enter.
Matt D
0

Sposobem na zrobienie tego (trochę, musisz wcisnąć przycisk zamiast klawisza, ale wystarczająco blisko) jest użycie błyszczącego:

library(shiny)

ui     <- fluidPage(actionButton("button", "Press the button"))
server <- function(input, output) {observeEvent(input$button, {stopApp()})}

runApp(shinyApp(ui = ui, server = server))

print("He waited for you to press the button in order to print this")

Z mojego doświadczenia wynika, że ​​ma to unikalną cechę: nawet jeśli uruchomiłeś skrypt, który miał kod napisany zgodnie z runAppfunkcją, nie uruchomi się, dopóki nie naciśniesz przycisku w aplikacji (przycisk, który zatrzymuje aplikacje od wewnątrz stopApp).

Sébastien Wouters
źródło