[C++] 325 BBS閲覧アプリの製作 その11 スレッドタイトルのGUI表示 Fl_Table 本表示

[M1 Mac, MacOS Ventura 13.3.1, clang 14.0.3]

スレッドタイトル一覧を表示させました。

自分なりに色々手を入れてC++らしくしたかったのですが上手くいかないので、C言語風味を残す形にしました。

今回のアプリ製作では最大の山場かもしれません。かなり手こずりました。

あとはスレッドタイトルをクリックして、右下にスレッド内容を表示させるだけです。

#include "cppstd.h" // 自製ライブラリ
#include "FLstd.h" // 自製ライブラリ
#include <WidgetTable.h>

extern vector<tuple<string, string, string, string>> numTitlePostnumID;
extern string id, num, title, postnum;

WidgetTable::WidgetTable(int x, int y, int w, int h, const char *l) : Fl_Table(x,y,w,h,l){
    col_header(1);
    col_resize(1);
    col_header_height(25);
    // row_header(1);
    row_resize(1);
    row_header_width(80);
    end();
}

WidgetTable::~WidgetTable(){}

void WidgetTable::SetSize(int newrows, int newcols) {
    clear();		// clear any previous widgets, if any
    rows(newrows);
    cols(newcols);

    col_width(0, 50);
    col_width(1, 1160-50-50-100);
    col_width(2, 50);
    col_width(3, 100);

    begin();		// start adding widgets to group
    {
      for ( int r = 0; r<newrows; r++ ) {
        for ( int c = 0; c<newcols; c++ ) {
            int X,Y,W,H;
            find_cell(CONTEXT_TABLE, r, c, X, Y, W, H);

            // switch文でも可
            if (c == 0) {
                char s[20];
                num = get<0>(numTitlePostnumID[r]);
                sprintf(s, "%s", num.c_str());
                Fl_Input *in = new Fl_Input(X,Y,W,H);
                in->value(s);
            } else if(c == 1) {
                char s[200];
                title = get<1>(numTitlePostnumID[r]);
                sprintf(s, "%s", title.c_str());
                Fl_Input *in = new Fl_Input(X,Y,W,H);
                in->value(s);
            } else if(c == 2){
                char s[20];
                postnum = get<2>(numTitlePostnumID[r]);
                sprintf(s, "%s", postnum.c_str());
                Fl_Input *in = new Fl_Input(X,Y,W,H);
                in->value(s);
            } else if (c == 3){
                char s[20];
                id = get<3>(numTitlePostnumID[r]);
                sprintf(s, "%s", id.c_str());
                Fl_Input *in = new Fl_Input(X,Y,W,H);
                in->value(s);
            }
        }
      }
    }
    end();
  }

void WidgetTable::draw_cell(TableContext context, 
			  int R, int C, int X, int Y, int W, int H) {
  switch ( context ) {
    case CONTEXT_STARTPAGE:
      fl_font(FL_HELVETICA, 12);		// font used by all headers
      break;

    case CONTEXT_RC_RESIZE: {
      int X, Y, W, H;
      int index = 0;

      for ( int r = 0; r<rows(); r++ ) {
        for ( int c = 0; c<cols(); c++ ) {
            if ( index >= children() ) break;
            find_cell(CONTEXT_TABLE, r, c, X, Y, W, H);
            child(index++)->resize(X,Y,W,H);
        }
      }
      init_sizes();			// tell group children resized
      return;
    }

    case CONTEXT_ROW_HEADER:
      fl_push_clip(X, Y, W, H);
      {
        static char s[40];
        sprintf(s, "Row %d", R);
        fl_draw_box(FL_THIN_UP_BOX, X, Y, W, H, row_header_color());
        fl_color(FL_BLACK);
        fl_draw(s, X, Y, W, H, FL_ALIGN_CENTER);
      }
      fl_pop_clip();
      return;

    case CONTEXT_COL_HEADER:
      fl_push_clip(X, Y, W, H);
      {
        if (C == 0){
            static char s[40];
            sprintf(s, "番号");
            fl_draw_box(FL_THIN_UP_BOX, X, Y, W, H, col_header_color());
            fl_color(FL_BLACK);
            fl_draw(s, X, Y, W, H, FL_ALIGN_CENTER);
        } else if (C == 1){
            static char s[40];
            sprintf(s, "タイトル");
            fl_draw_box(FL_THIN_UP_BOX, X, Y, W, H, col_header_color());
            fl_color(FL_BLACK);
            fl_draw(s, X, Y, W, H, FL_ALIGN_CENTER);
        } else if (C == 2){
            static char s[40];
            sprintf(s, "レス数");
            fl_draw_box(FL_THIN_UP_BOX, X, Y, W, H, col_header_color());
            fl_color(FL_BLACK);
            fl_draw(s, X, Y, W, H, FL_ALIGN_CENTER);
        } else if (C == 3){
            static char s[40];
            sprintf(s, "ID");
            fl_draw_box(FL_THIN_UP_BOX, X, Y, W, H, col_header_color());
            fl_color(FL_BLACK);
            fl_draw(s, X, Y, W, H, FL_ALIGN_CENTER);
        }
        
      }
      fl_pop_clip();
      return;

    case CONTEXT_CELL:
      return;		// fltk handles drawing the widgets

    default:
      return;
  }
}

[C++] 324 BBS閲覧アプリの製作 その10 スレッドタイトルのGUI表示 Fl_Table 仮表示

[M1 Mac, MacOS Ventura 13.3.1, clang 14.0.3]

Fl_Tableを継承したWidgetTableクラスを使い、スレッドタイトル一覧表示の土台を作成しました。

クラスの作成は久しぶりだったので、少々手こずりました。

FLTKについてはChatGPTは余りあてにならず、ソースコードにあるサンプルを参考にしています。

ようやくゴールが見えてきた感じです。

#include "cppstd.h" // 自製ライブラリ
#include <FLstd.h>
#include <FL/Fl.H>
#include <FL/Fl_Double_Window.H>
#include <FL/Fl_Tree.H>
#include "getBoard.h"
#include "WidgetTable.h"

int main(int argc, char *argv[]) {
  Fl_Double_Window *win = new Fl_Double_Window(1400, 1020, "BBS Browser");

  win->begin();
  {
    // Create the tree
    Fl_Tree* tree = new Fl_Tree(10, 45, 230, win->h()-45-10);
    tree->showroot(0);

    vector<tuple<string, string, string>> idTitleCat = getBoard();
    vector<string> categories;

    for (const auto& element : idTitleCat) {
        string path = get<2>(element) + "/" + get<1>(element);
        cout << "path: " << path << endl;

        string category = get<2>(element);
    
        if (find(categories.begin(), categories.end(), category) == categories.end()) {
            tree->add(category.c_str())->close();
            categories.push_back(category);
        }

        tree->add(path.c_str());
    }

    WidgetTable* table = new WidgetTable(240, 45, 1400-230-10, 350, "");
    table->SetSize(5, 5);

  }
  win->end();

  win->resizable(win);
  win->show(argc, argv);
  return(Fl::run());
}

[C++] 323 BBS閲覧アプリの製作 その9 ボードタイトルのGUI表示 Fl_Tree

[M1 Mac, MacOS Ventura 13.3.1, clang 14.0.3]

いよいよGUIの作成に取りかかります。

FLTKのFl_Treeを使ってボードタイトルをカテゴリーごとにツリー表示できるようにしました。

今回はChatGPTをほとんど使わず、FLTKのtestコードを参考にしました。

なお、自製ライブラリcppstd.hでusing std::stringなどを設定しているのでstd::は省略されています。そうしないと可読性が著しく低くなります。

C++版がある程度形になったらSwiftへの移植も考えています。

#include "cppstd.h" // 自製ライブラリ
#include <stdio.h>
#include <FL/Fl.H>
#include <FL/Fl_Double_Window.H>
#include <FL/Fl_Tree.H>
#include "getBoard.h"

int main(int argc, char *argv[]) {
  Fl_Double_Window *win = new Fl_Double_Window(1400, 1050, "BBS Browser");
  win->begin();
  {
    // Create the tree
    Fl_Tree *tree = new Fl_Tree(10, 10, 230, win->h()-20);
    tree->showroot(0);

    vector<tuple<string, string, string>> idTitleCat = getBoard();
    vector<string> categories;

    for (const auto& element : idTitleCat) {
        string path = get<2>(element) + "/" + get<1>(element);
        cout << "path: " << path << endl;

        string category = get<2>(element);
    
        if (find(categories.begin(), categories.end(), category) == categories.end()) {
            tree->add(category.c_str())->close();
            categories.push_back(category);
        }

        tree->add(path.c_str());

    }

  }
  win->end();
  win->resizable(win);
  win->show(argc, argv);
  return(Fl::run());
}