1

应用程序

启动时,会生成一个 3 x 3 的表格,其中的值从 1 到 9 以随机顺序排列。应用程序用户可以看到的是一个空白的 3 x 3 rhandsontable,他/她将使用它来尝试猜测生成的值在哪里。当用户单击“提交”按钮时,包含正确值的单元格变为绿色,所有其他单元格保持原样。

我的问题

当用户单击按钮时,用户猜对的单元格不会变成绿色。换句话说,即使我以前让它工作,条件格式也不起作用(那是在我没有使用闪亮模块的应用程序的第一个版本中)。

我做了什么

完整项目位于以下 Github 存储库中,潜在用户可能希望克隆而不是复制和粘贴以下代码:https ://github.com/gueyenono/number_game

我的项目文件夹有 4 个文件。前两个文件是通常的ui.Rand server.R,它们本质上称为闪亮的模块(即hot_module_ui()hot_module())。模块包含在global.R文件中。最后一个文件 ,update_hot.R包含模块中使用的函数。

用户界面

此文件加载所需的包,为应用程序提供标题并调用hot_module_ui(). 该模块仅显示一个空白 3 x 3rhandsontable和一个actionButton().

library(shiny)
library(rhandsontable)
source("R/update_hot.R")

ui <- fluidPage(

  titlePanel("The number game"),

  mainPanel(
    hot_module_ui("table1")
  )
)

服务器.R

此文件调用hot_module(),其中包含条件格式的代码。

server <- function(input, output, session) {
  callModule(module = hot_module, id = "table1")
}

update_hot.R

这是调用“提交”按钮时调用的函数。该函数有两个参数:

  • hot:应用程序中的handsontable
  • x:启动时生成的值

这就是函数的作用(文件的完整代码在本节末尾):

  1. 获取用户输入
user_input <- hot_to_r(hot)
  1. 将用户输入 ( user_input) 与真实值 ( x) 进行比较,并存储用户猜对的单元格的行和列索引
i <- which(user_input == x, arr.ind = TRUE)

  row_correct <- i[, 1] - 1
  col_correct <- i[, 2] - 1
  1. 使用行和列索引更新当前可操作对象,并使用函数的renderer参数hot_cols()使相应单元格的背景变为绿色。请注意,我使用该hot_table()函数来更新现有rhandsontable对象。
hot %>%
    hot_table(contextMenu = FALSE, row_correct = row_correct, col_correct = col_correct) %>%
    hot_cols(renderer = "function(instance, td, row, col, prop, value, cellProperties){
          Handsontable.renderers.TextRenderer.apply(this, arguments);

          if(instance.params){

            // Correct cell values
            row_correct = instance.params.row_correct
            row_correct = row_correct instanceof Array ? row_correct : [row_correct]
            col_correct = instance.params.col_correct
            col_correct = col_correct instanceof Array ? col_correct : [col_correct]


            for(i = 0; i < col_correct.length; i++){ 
              if (col_correct[i] == col && row_correct[i] == row) {
                  td.style.background = 'green';
              } 
            }

          return td;
        }")

这是完整的代码update_hot.R

update_hot <- function(hot, x){

  # Get user inputs (when the submit button is clicked)
  user_input <- hot_to_r(hot)

  # Get indices of correct user inputs
  i <- which(user_input == x, arr.ind = TRUE)

  row_correct <- i[, 1] - 1
  col_correct <- i[, 2] - 1

  # Update the hot object with row_index and col_index for user in the renderer
  hot %>%
    hot_table(contextMenu = FALSE, row_correct = row_correct, col_correct = col_correct) %>%
    hot_cols(renderer = "function(instance, td, row, col, prop, value, cellProperties){
          Handsontable.renderers.TextRenderer.apply(this, arguments);

          if(instance.params){

            // Correct cell values
            row_correct = instance.params.row_correct
            row_correct = row_correct instanceof Array ? row_correct : [row_correct]
            col_correct = instance.params.col_correct
            col_correct = col_correct instanceof Array ? col_correct : [col_correct]


            for(i = 0; i < col_correct.length; i++){ 
              if (col_correct[i] == col && row_correct[i] == row) {
                  td.style.background = 'green';
              } 
            }

          return td;
        }")
}

全局.R

这是包含闪亮模块的文件。UI模块 (hot_module_ui()_ rHandsontableOutput _actionButtontableOutput

每当用户单击“提交”按钮时,服务器模块 ( hot_module()) 调用该update_hot()函数并尝试更新应用程序中的掌上电脑。我试图通过使用一个observeEvent和一个反应值来实现这一点react$hot_display。启动时,react$hot_display包含NAs 的 3 x 3 数据帧。单击该按钮时,它会更新为新版本的handsontable(包含用户输入和条件格式)。这是完整的代码global.R

hot_module_ui <- function(id){

  ns <- NS(id)

  tagList(
    rHandsontableOutput(outputId = ns("grid")),
    br(),
    actionButton(inputId = ns("submit"), label = "Submit"),
    br(),
    tableOutput(outputId = ns("df"))
  )

}


hot_module <- function(input, output, session){

  values <- as.data.frame(matrix(sample(9), nrow = 3))

  react <- reactiveValues()

  observe({
    na_df <- values
    na_df[] <- as.integer(NA)
    react$hot_display <-  rhandsontable(na_df, rowHeaders = NULL, colHeaders = NULL)
  })

  observeEvent(input$submit, {
    react$hot_display <- update_hot(hot = input$grid, x = values)
  })

  output$grid <- renderRHandsontable({
    react$hot_display
  })

  output$df <- renderTable({
    values
  })
}

如开头所述,单击“提交”按钮时条件格式不起作用,我不知道为什么。再次,您可以访问以下 Github 存储库中的完整代码:

https://github.com/gueyenono/number_game

4

1 回答 1

1

我终于找到了解决我的问题的方法。我学到的最大教训之一是该hot_to_r()函数在自定义函数中不起作用。它必须在闪亮应用程序的服务器功能中使用。这意味着将rhandsontable对象传递给自定义函数并从函数中检索数据可能不是一个好主意(这是我的故事)。

我不确定任何人都会对它感兴趣,但这是我的代码,它按预期工作:

用户界面

library(rhandsontable)
library(shiny)
source("R/update_hot.R")

shinyUI(fluidPage(

    # Application title
    titlePanel("The Number Game"),

    module_ui(id = "tab")
))

服务器.R

library(shiny)

shinyServer(function(input, output, session) {

    callModule(module = module_server, id = "tab")

})

全局.R

module_ui <- function(id){

  ns <- NS(id)

  tagList(
    rHandsontableOutput(outputId = ns("hot")),
    actionButton(inputId = ns("submit"), label = "OK"),
    actionButton(inputId = ns("reset"), label = "Reset")
  )
}


module_server <- function(input, output, session){

  clicked <- reactiveValues(submit = FALSE, reset = FALSE)

  initial_hot <- rhandsontable(as.data.frame(matrix(NA_integer_, nrow = 3, ncol = 3)))
  correct_values <- as.data.frame(matrix(1:9, nrow = 3, byrow = TRUE))

  observeEvent(input$submit, {
    clicked$submit <- TRUE
    clicked$reset <- FALSE
  })

  updated_hot <- eventReactive(input$submit, {
    input_values <- hot_to_r(input$hot)
    update_hot(input_values = input_values, correct_values = correct_values)
  })


  observeEvent(input$reset, {
    clicked$reset <- TRUE
    clicked$submit <- FALSE
  })

  reset_hot <- eventReactive(input$reset, {
    initial_hot
  })


  output$hot <- renderRHandsontable({

    if(!clicked$submit & !clicked$reset){
      out <- initial_hot
    } else if(clicked$submit & !clicked$reset){
      out <- updated_hot()
    } else if(clicked$reset & !clicked$submit){
      out <- reset_hot()
    }

    out
  })
}

R/update_hot.R

update_hot <- function(input_values, correct_values){

  equal_ids <- which(input_values == correct_values, arr.ind = TRUE)
  unequal_ids <- which(input_values != correct_values, arr.ind = TRUE)

  rhandsontable(input_values) %>%
    hot_table(row_correct = as.vector(equal_ids[, 1]) - 1,
              col_correct = as.vector(equal_ids[, 2]) - 1,
              row_incorrect = as.vector(unequal_ids[, 1]) - 1,
              col_incorrect = as.vector(unequal_ids[, 2]) - 1) %>%

    hot_cols(renderer = "function(instance, td, row, col, prop, value, cellProperties){
          Handsontable.renderers.TextRenderer.apply(this, arguments);

          if(instance.params){

            // Correct cell values
            row_correct = instance.params.row_correct
            row_correct = row_correct instanceof Array ? row_correct : [row_correct]
            col_correct = instance.params.col_correct
            col_correct = col_correct instanceof Array ? col_correct : [col_correct]

            // Incorrect cell values
            row_incorrect = instance.params.row_incorrect
            row_incorrect = row_incorrect instanceof Array ? row_incorrect : [row_incorrect]
            col_incorrect = instance.params.col_incorrect
            col_incorrect = col_incorrect instanceof Array ? col_incorrect : [col_incorrect]


            for(i = 0; i < col_correct.length; i++){ 
              if (col_correct[i] == col && row_correct[i] == row) {
                  td.style.background = 'green';
              } 
            }

            for(i = 0; i < col_incorrect.length; i++){ 
              if (col_incorrect[i] == col && row_incorrect[i] == row) {
                  td.style.background = 'red';
              } 
            }
          }
          return td;
        }")
}
于 2019-06-12T00:36:40.660 回答