简体   繁体   中英

Clearing a field buffer in ncurses

I've built a generic wrapper for the curses form object to use with a large simulation project that I'm working on.

Basically, I instantiate an generic_form object, add some fields and their descriptions to it, and then give it focus and get user input with a fill_form() routine.

Because each generic_form object can be used more than once, that is, that fill_form() may be called more than once per instantiation, I need to clear the field buffers at the beginning of the fill_form() routine. Currently, I'm using this at the beginning of the routine:

//clear the field buffers in case there's junk in them
    for (std::vector<FIELD*>::iterator clear_iter = fields.begin();
            clear_iter != fields.end(); clear_iter++)
    {
        if (*clear_iter != nullptr)
        {
            set_field_buffer(*clear_iter, 0, " ");
        }
    }

However, it throws a floating point exception at the set_field_buffer line on the second call to the fill_form() routine. Moreover, the set_field_buffer line doesn't seem to actually be doing anything, at least not clearing the buffer, because without calling free_field at the end of the routine, and instead in the object destructor, the fields buffers remain the same on each subsequent call.

Here's the entirety of the (ugly, in-development) fill_form() routine for brevity:

void generic_form::fill_form()
{
    //fields.push_back(NULL);
    if (fields.size() == 1)
    {
        fields.push_back(NULL);
        form = new_form(static_cast<FIELD**>(fields.data()));
        fields.erase((fields.end() - 1));
        assert(fields.size() == 1);
    }
    else
    {
        form = new_form(static_cast<FIELD**>(fields.data()));
    }
    WINDOW* form_win = derwin(screen, fields.size() + 1, largest_desc + 6, ypos, 
            xpos);
    set_form_win(form, form_win);
    set_form_sub(form, form_win);
    //clear the field buffers in case there's junk in them
    for (std::vector<FIELD*>::iterator clear_iter = fields.begin();
            clear_iter != fields.end(); clear_iter++)
    {
        if (*clear_iter != nullptr)
        {
            set_field_buffer(*clear_iter, 0, " ");
        }
    }
    post_form(form);
    for (int x = 0; x < descriptions.size(); x++)
    {
        mvwprintw(form_win, x, 0, descriptions.at(x).c_str());
    }
    wmove(form_win, 0, largest_desc + 1);
    touchwin(screen);
    wrefresh(form_win);
    /* Loop through to get user requests */
    int ch;
    while((ch = getch()) != '\n')//KEY_F(1))
    {   switch(ch)
            {       
            case KEY_DOWN:
                    /* Go to next field */
                    form_driver(form, REQ_NEXT_FIELD);
                    /* Go to the end of the present buffer */
                    /* Leaves nicely at the last character */
                    form_driver(form, REQ_END_LINE);
                    break;
            case KEY_UP:
                    /* Go to previous field */
                    form_driver(form, REQ_PREV_FIELD);
                    form_driver(form, REQ_END_LINE);
                    break;
            case KEY_LEFT:
                    form_driver(form, REQ_PREV_CHAR);
                    break;
            case KEY_RIGHT:
                    form_driver(form, REQ_NEXT_CHAR);
                    break;

            // Delete the char before cursor
            case KEY_BACKSPACE:
            case 127:
                    form_driver(form, REQ_DEL_PREV);
                                break;

            // Delete the char under the cursor
            case KEY_DC:
                    form_driver(form, REQ_DEL_CHAR);
                    break;
            default:
                    /* If this is a normal character, it gets */
                    /* Printed                */    
                    form_driver(form, ch);
                    break;
            }
    }
    form_driver(form, REQ_VALIDATION);
    for (int x = 0; x < fields.size() && first_run; x++)
    {
        //store the int_inputs from the forms
        if ((fields.at(x) != nullptr) && (field_type(fields.at(x)) ==
                TYPE_INTEGER))
        {
            int_inputs.push_back(std::atoi(field_buffer((fields.at(x)), 0)));
        }
        if ((fields.at(x) != nullptr) && (field_type(fields.at(x)) ==
                TYPE_ALPHA))
        {
            str_inputs.push_back(field_buffer((fields.at(x)), 0));
        }
    }
    first_run = false;
    /* Un post form and free the memory */
    unpost_form(form);
    free_form(form);
    for (int x = 0; x < fields.size(); x++)
    {
        free_field(fields.at(x));
    }
    delwin(form_win);
}

Long story short/TLDR: How to I clear or reset a field buffer in ncurses, without deleting and re-adding it?

You can clean field buffer using form_driver ()

Excerpt man form_driver

REQ_CLR_EOL
   Clear to end of line from cursor.

REQ_CLR_EOF
   Clear to end of field from cursor.

REQ_CLR_FIELD
   Clear the entire field.

To elaborate this a bit more :-), I'm using code similar to following for clearing fields:

#include <stdio.h>
#include <stdlib.h>
#include <form.h>

enum f_name_l
{
  f_name, f_surname, f_last
};

int main (void)
{
  int ch = 0, i = 0;
  FIELD *field[3], *save_field;
  FORM *my_form;

  initscr ();
  start_color ();
  noecho ();
  raw ();
  keypad (stdscr, TRUE);
  refresh ();

  field[f_name] = new_field (1, 10, 0, 25, 0, 0);
  field[f_surname] = new_field (1, 10, 2, 25, 0, 0);
  field[f_last] = NULL;

  set_field_back (field[f_name], A_UNDERLINE);
  set_field_back (field[f_surname], A_UNDERLINE);

  my_form = new_form (field);
  post_form (my_form);

  // Form labels
  mvprintw (0, 1, "Name: ");
  mvprintw (2, 1, "Surname: ");
  mvprintw (4, 1, "F5 to clear active field. F6 to clear form.");

  pos_form_cursor (my_form);

  refresh ();

  // ^q to exit
  while ((ch = getch ()) != 17)
  {
    switch (ch)
    {
      case KEY_UP:
        form_driver (my_form, REQ_PREV_FIELD);
      break;
      case KEY_DOWN:
        form_driver (my_form, REQ_NEXT_FIELD);
      break;
      case KEY_F(5):
        form_driver (my_form, REQ_CLR_FIELD);
      break;
      case KEY_F(6):
        save_field = current_field (my_form);

        for (i = 0; i < f_last; i++)
        {
          set_current_field (my_form, field[i]);
          form_driver (my_form, REQ_CLR_FIELD);
        }

        set_current_field (my_form, save_field);
      break;
      default:
        form_driver (my_form, ch);
      break;
    }

    form_driver (my_form, REQ_VALIDATION);
  }

  endwin ();

  return EXIT_SUCCESS;
}

But seeing post from Thomas Dickey I start to feel like my life is a lie :-).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM