だら$ちっぷす

仕事の覚書です

C#はじめました。まずはフォーム画面を作ってみる。

C#はじめます。

まずは何をすればええのじゃー。
まったく何もしりません。(C使い、Delphi使いではあります)

調べてみたところ、C#.Net Framework 上で動くらしい?
.Net Frameworkは、winidowsマシンやったら気にせんでも入ってるらしい?
C#Visual Studioで開発するといいらしい?
Visual Studioを入れると、C#も入るらしい?

てなわけで、Visual Studio2022を入れてみました。

learn.microsoft.com
まずはフォーム画面を作ってみよう。

learn.microsoft.com
うーん?
Windowsフォームアプリ」と「Windowsフォームアプリケーション (.NET Framework)」てのがあるけど、どっちを選べばいいのかなあ?
上記、レッスンでは「アプリケーション」の方やけど、自分の目的と合ってるのかなあ?

impsbl.hatenablog.jp
こちらの記述がわかり易かったです!
素直に「Windowsフォームアプリケーション (.NET Framework)」を選ぼうと思います!

新規ソリューションを作った。




上記、MSのサイトに書かれてる通りにやってみます。


(・3・) ツールボックス、どこにあんの?


左の赤丸「ツールボックス」をクリックして、右の赤丸「ピンを刺して」、真ん中の赤丸「コモンコントロール」の下が、画面に貼り付けられる部品です。


(・3・) プロパティ、どこにあんの?


「表示」→「プロパティウィンドウ」


(・3・) 実行メニュー、どこにあんの?


なんか、右の赤丸のとこ、ピッてやったら出た!!
わからんわそんなもん!!><、、、


作った!!



走らした!!


perplexity.ai が良いと聞いたので。後、chrome拡張の追加の仕方。

perplexity.ai が良いと聞いたので試してみようと思った。
でも、どうやったら使えるの?
全然わからないのでぐぐってみたらChromeに入れろって書いてある。
なんかchrome検索エンジンに追加したら良いとか。。。
書かれてる通りにやってみたが、書かれてるようにうまくいかない・3・
うーん・・・
初心に戻って(初心なかったんですけど)googleさんで「perplexity.ai」て検索してみた

perplexity.ai

普通にperplexity.aiのサイトに飛ぶよねーw
そらそうや。変なとこから入ったから考えてなかった。申し訳ない。
いや、githubとかそういうやつかなーと思ってたんで手順サイトで教えてもらった方が早いかと思って。。。すみません><;

このまま使ってもええんやけど、なんかクロム拡張が用意されてるみたいなんで、せっかくなので入れてみることにした。初心貫徹?(違w)

右上の「chrome extension」をクリック




ウェブストアサイトに飛ばされる。ここで「chromeに追加」




拡張しますか?と聞かれるので「拡張機能を追加」する



追加されましたー。簡単簡単^^




追加したけど、どうやって使うの?(・・?
ようわからんので、上んとこにアイコンを表示しとくことにしましたー^^;

これを。。。

こうじゃ!


後は、アイコンをクリックしたら検索画面がぺろーんと出てくるんで質問を入力する
こんな感じー



でも、これだと、普通にperplexity.aiのサイトで検索するんとあんま変わりないよね?
なんかユーザ数少なくない?って思ったんだけど、そういうことかなー?
まあ、いいや。
とりま、色々使ってみますー^^


Node.jsでローカルサーバを立てる

ちょっとしたwebツールを作るのにファイル操作めんどいからnodeでやったれと思って久々にメインから書きはじめたら全然忘れてた(;´д`)のでメモ。

/*
  tool1.js
  起動テスト
*/

//起動アドレス
const ip = "127.0.0.1";    //localhost
const port = 30303;   //テキトー(未だに何番使えば笑われなくて済むのかわからん)

//expressモジュール
const express = require('express');
const app = express();

//appでjson送る時はこの2つが必要(送れるサイズをでかくする。デフォルトは100kb)
app.use(express.json({ extended: true, limit: '10mb' }));
app.use(express.urlencoded({ extended: true, limit: '10mb' }));


//https鯖を起動
try
{
    app.listen(port, ip, () =>
    {
        console.log('http server ' + ip + ":" + port)
    });
}
catch(err)
{
    console.log("鯖起動エラー", err);
    process.exit(1);
}

//確認
app.get('/', async (req, res, next) => 
{
    res.send('動作確認。わたしの好きな言葉です^^');
});



これを起動

>node tool1.js
http server 127.0.0.1:30303



ブラウザで表示

URL[ http://localhost:30303 ]
動作確認。わたしの好きな言葉です^^



よしよし。ええ感じや^^

続けて、POSTのテストをします。
以下のルーチンを tool1.js に追加。

//POST確認
app.post('/situmon', async (req, res, next) => 
{
    let ans = {};
    switch(req.body.situmon)
    {
        case "like":
            ans.kotae = "動作確認。わたしの好きな言葉です^^";
            break;
        case "hate":
            ans.kotae = "仕様変更。わたしの苦手な言葉です><";
            break;
        default:
            ans.kotae = "・・・・・(V)o\\o(V)ふぉっふぉっふぉ";
    }
    res.setHeader('Content-Type', 'application/json');
    res.write(JSON.stringify(ans));
    res.end();
});



POSTはfetchで発行するんで、少々テストがめんどいっす><;
こんなHTMLを作ってみました。

<!DOCTYPE html>
<html>
<!------------------------------------------------------------------------------
    test1.html
-------------------------------------------------------------------------------->
<head>
    <meta charset="UTF-8">
    <title>test1</title>
    <style>
        div > div
        {
            display: flex;              /*センタリング */
            align-items: center;        /*センタリング */
            justify-content: center;    /*センタリング */
            background-color:#fffaf0;
            border: solid #4682b4;
            border-radius: 8px;
            cursor:pointer;
            margin-top:8px;
            width:100px;
            height:30px;
            margin: 50px 2px 0px 2px;
        }
    </style>
</head>
<body>
    <div style="display:flex;justify-content: center;align-items: center;">
        <div onClick="situmon('like')">好きな言葉</div>
        <div onClick="situmon('hate')">苦手な言葉</div>
        <div onClick="situmon('')">無言</div>
    </div>
    <div id="id_kotae">
        <!-- ここに回答を書く -->
    </div>
</body>
</html>

<script>
async function situmon(word)
{
    let str = "";

    try
    {
        //送るデータ
        let reqData = 
        {
            situmon:    word
        };

        //送受信
        const res = await fetch(
                        "http://localhost:30303/situmon", 
                        {
                            method:     'POST',
                            body:       JSON.stringify(reqData), 
                            headers:    {'Content-Type': 'application/json'}
                            credentials:'include',
                            mode:       'cors'
                        });
        //受けたデータ
        if(res.ok)
        {
            const resData = await res.json();
            str = resData.kotae;
        }
        else
        {
            str = "[POST ERROR] " + res.statusText;
        }
    }
    catch(err)
    {
        str = "[FETCH ERROR] " + err;
    }

    id_kotae.innerHTML = str;
}
</script>



test1.htmlをダブルクリックするとchrome画面が立ち上がる。(うちはwindowschrome使てますからー)
適当なボタンをポチッとな。

・・・・ぐあああああああ!!!!::: (ノ'A`)>:::
出たなーーー!!!クロスオリジンめーーーーー!!!!!=͟͟͞͞⊂( ‘ω’∩ )

fetch使たらクロスオリジンでるんやったっけ。ちぇ。・3・
test1.jsに以下の2行を付け加える。

//https鯖を起動
try
{
    //CORSを許可する(fetchを使うために必要)
    const cors = require('cors');
    app.use(cors({ origin: true, credentials: true }));


    app.listen(port, ip, () =>
    {
        console.log('http server ' + ip + ":" + port)
    });
}
catch(err)
{
    console.log("鯖起動エラー", err);
    process.exit(1);
}



よし!再起動だ!(`・ω・´)ゞ
再起動。わたしの好きな言葉です。
HTMLをダブルクリックして、ボタンポチ~( ・∀・)つ〃∩


うまく行ったー!!(∩´∀`)∩ワーイ(∩´∀`)∩ワーイ

以上です!(`・ω・´)ゞ
※これはローカル専用です。セキュリティもへったくれも考えてないです。

Node.js でURLの引数とか

多分めっちゃ初歩的なことなんだけど、毎回忘れてぐぐるんで、ここに書いておく

こういうURLのとき
https://~~~/page?user_id=[A]&user_name=[B]

router.get('/', async (req, res) =>
{
    if(req.query.user_id == undefined)
    {
        console.log("エラーですやん");
        return;とか
    }
    var user_id = req.query.user_id;

    if(req.query.user_name == undefined)
        var mode = "ななしー";
    else
        var mode = req.query.user_name;
});



こういうURLのとき
https://~~~/page/[A]/[B]

router.get('/:user_id/:user_name', async (req, res) =>
{
    if(req.params.user_id == undefined)
    {
        console.log("エラーですやん");
        return;とか
    }
    var user_id = req.params.user_id;

    if(req.params.user_name == undefined)
        var mode = "ななしー";
    else
        var mode = req.params.user_name;
});

あー。なんか、一番上からの:はあかんみたい。そらそうか。全部になってまうもんなー。

わかった!! 一番上からの:があかんのではなくて、2つとも:だと、何もかもになってしまうのでだめでした

こういうURLだったらいける
https://~~~/page/[A]/user_name

router.get('/:user_id/user_name', async (req, res) =>
{
    if(req.params.user_id == undefined)
    {
        console.log("エラーですやん");
        return;とか
    }
    var user_id = req.params.user_id;

});

node.js セッション ログイン状態を持続する

いっぺんログインしたクライアントは2回め以降ログインせんでもいけるようにしてーと言われたので調べた
(のを書いてなかったみたいなので書いとく。1年前のやつですが今んとこまだ使えてます)

セッションを定義して、サーバを起動する(日本語変かもー)

   //CORSを許可する
    const cors = require('cors');
    app.use(cors({ origin: true, credentials: true }));

    //セッション定義
    const session = require('express-session');
    var sess = 
    {
        secret:             'keyboard cat',
        resave:             false,
        saveUninitialized:  false, 
        cookie: 
        {
            maxAge:     24 * 60 * 60 * 1000,    //1日有効 
            sameSite:   'none',
            secure:     true       //←httpsのときしかクッキーを通さないモード
                                 //  これをtrueにしておかないとchromeでエラーになる
        }
    };
    app.use(session(sess));


    //session(cookie)を使うためにhttpsにする
    const fs = require('fs');
    const options = 
    {
        key:    fs.readFileSync('xxx.key'),    //セキュリティ証明書
        cert:   fs.readFileSync('xxx.crt')      //KEYファイル
    };
    const https = require('https');
    const server = https.createServer(options, app);
    server.listen(3000, () => 
    {
        console.log('https server listening port 3000')
    });


セッションって、クッキー使ってやるのねー。しらんかったー(^^;
クライアント側、ログイン要求。こんな感じで。

   data.name = "ログイン名";
    const res = await fetch("https://localhost:3000/login",
            {
                method:     'POST',
                body:       JSON.stringify(data), 
                headers:        {'Content-Type': 'application/json'},
                credentials:    'include',
                mode:       'cors'
            });


サーバ側、ログイン受信処理

router.post('/login', async (req, res, next) => 
{
    //セッションにセット
    req.session.login = 
    {
        user_name:  req.body.name
    };
    res.end();
}


サーバ側、以降、必ずログイン名がくっついて来る

router.post('/nanka_suru', async (req, res, next) => 
{
    if (req.session != undefined && req.session.login != undefined)
        console.log(req.session.login.user_name);  //ログイン名
    res.end();
});


ログアウトのときは、無効な値をセットしておけばよい
以下のようにしておけば、次に nanka_suru が呼ばれたときに、req.session.login == undefined になって、ログインしてないことがわかる

router.post('/logout', async (req, res, next) => 
{
    if (req.session != undefined && req.session.login != undefined)
        req.session.login = undefined;
    res.end();
});


なんか特別なログイン・ログアウトの仕組みがあるんかと思ってたけど、普通に自分でやればいいだけだったみたい^^

matter.jsを使ってみる

タワーバトルっぽいのを作ってみようと思ったんで、物理演算ライブラリとかないかなーとググってたら「物理エンジン」というワードを見つけた
物理エンジンで探してみたら、PhysX とか Bullet とかの名前を見かけたんだけど、これらはVSとかpythonのようだ
別にそれでもいいんだけど鯖なくても使えるのがいいなー。javascriptでないかなー?
で、matter.jsを見つけました!あと、Box2D。行き詰まったらこっちも試してみよう


brm.io


トップページの「Source Code」をクリック

  f:id:daralib:20201116114039j:plain

「releases」をクリック

  f:id:daralib:20201116114330j:plain

zipなりtarなり落として解凍

  f:id:daralib:20201116114530j:plain

解凍したフォルダの下のbuildの下のmatter.min.jsを任意の場所に置いて、htmlにインクルードしてやればOK

HTML部分は、こんな感じ

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title>matter.js 使ってみる</title>
   <script src="matter.min.js"></script>
</head>
<body>
    <div id="id_container" style="width:640px;height:480px;border:solid 2px #008000">
        <!-- 描画コンテナ -->
    </div>
</body>
</html>



スクリプト部分

<script>
//---------------------
// 画面起動時
//---------------------
window.addEventListener("DOMContentLoaded", function()
{
    //matter初期設定
    matter_init();

    //床とか壁を作る
    make_static();

    //イベントリスナ作成(左ボタンを押下すると箱が出現する)
    id_container.addEventListener("mousedown", mousedown, {passive: true, capture: true});
});


//---------------------
// matter初期設定
//---------------------
var engineWorld; //物理エンジン

function matter_init()
{
    //物理エンジン作成
    const engine = Matter.Engine.create();
    engineWorld = engine.world;
    Matter.Engine.run(engine);

    //レンダラ作成
    const render = Matter.Render.create(
                {
                    element:    id_container,   //描画コンテナ
                    engine:     engine,         //物理エンジン
                    options:
                    {
                        width:      640,        //カンバスWidth(コンテナのサイズは反映されない)
                        height:     480,        //カンバスHeight(コンテナのサイズは反映されない)
                        background: "#ffffff",   //背景色(コンテナの色は反映されない)
                        wireframes: false,     //ワイヤフレームにしません
                    }
                });
    Matter.Render.run(render);
}


//---------------------
// 床とか壁を作る
//---------------------
function make_static()
{
    const table = Matter.Bodies.rectangle
    (
        320, 400, 100, 10,  //中心x, 中心y, 幅, 高さ
        {
            isStatic: true //固定する
        }
    );
    Matter.World.add(engineWorld, [table]);
}


//--------------------------------
// 左ボタンを押下したら箱を生成する
//--------------------------------
var click_cnt = 0;
function mousedown(ev)
{
    if(ev.button != 0)
        return;

    const block = Matter.Bodies.rectangle //四辺形
    (
        ev.offsetX, ev.offsetY, 80, 40,     //中心x, 中心y, 幅, 高さ
        {
            /* このあたりの数値が設定できると思われる。まだ試し中
           density         :   密度
           restitution     :   弾力
           friction        :   動摩擦
           frictionStatic  :   静止摩擦
           frictionAir     :   空気抵抗
           motion          :   運動
           slop            :   揺れ
           torque          :   ねじり
           */
            render:
            {
                sprite:
                {    //箱の表面に番号を描いた画像を貼り付ける
                    texture: make_image("" + ++click_cnt, 80, 40)
                }
            }
        }
    );
                        
    Matter.World.add(engineWorld, [block]);
}

//--------------------------------
// 番号を描いた画像を用意する
//--------------------------------
function make_image(str, w, h) 
{
    //カンバス作成
    let canv = document.createElement("canvas");
    canv.width = w;
    canv.height = h;

    //コンテキスト取得
    let ctx = canv.getContext("2d");

    //背景塗る
    ctx.fillStyle = "#ffc0cb";
    ctx.fillRect(0, 0, w, h);

    //字を描く
    ctx.fill();
    ctx.fillStyle = "#000000";
    ctx.textAlign = "center";
    ctx.fillText(str, w / 2, h / 2);

    //画像をurlに変換して返す
    return canv.toDataURL("image/png");
}
</script>



上記、実行できるやつそのままなんだけど、matter.jsが置けないので、はてな上で動かすんは無理かーと思いました。残念。

flexboxのまとめ

DIVの配置をHTML任せにする場合、避けて通れないflexbox
毎回忘れて1日がかりになってしまうので、ここにまとめておこうと思います


基本。そして最も使うやつ。DIVを横に並べます

<ポイント>
 親のDIVのstyleに追加
  display:flex;   flexboxですよ宣言。こいつの子供は横に並ぶよ

<div style="display:flex; border:solid 1px #008000;">
    <div style="background-color:#ff8888; width:100px; height:50px; margin-left:10px;"></div>
    <div style="background-color:#88ff88; width:100px; height:50px; margin-left:10px;"></div>
    <div style="background-color:#8888ff; width:100px; height:50px; margin-left:10px;"></div>
</div>



あーーーー。文字、真ん中にしたいやん
お任せくださいお嬢様。<( _ _ )彡
これもflexboxでちょちょいのちょいでございます(この後めちゃめちゃ時間食ったw)

<ポイント>
 本人のDIVのstyleに追加
  display:flex;       flexboxですよ宣言
  justify-content: center;  横の真ん中に配置
  align-items: center;    縦の真ん中に配置
  ※横に並べたいから親にもdisplay:flex;をつけてるけど、
   これは本人のセンタリングとは全く関係ないです。

<div style="display:flex; border:solid 1px #008000;align-items: center;">
    <div style="display:flex; justify-content: center; align-items: center; background-color:#ff8888; width:100px; height:50px; margin-left:10px;"></div>
    <div style="display:flex; justify-content: center; align-items: center; background-color:#88ff88; width:100px; height:50px; margin-left:10px;">臨兵闘者</div>
    <div style="display:flex; justify-content: center; align-items: center; background-color:#8888ff; width:100px; height:50px; margin-left:10px;">臨兵闘者皆陣烈在前</div>
</div>


臨兵闘者
臨兵闘者皆陣烈在前


んーーー。。。
display:flex;は、自分の子供に対して配置を指示するやつ、かな?
上記の場合、本人のセンタリングというより、本人の子供である文字列を本人の中にどう配置するか、ですね。
ちょっとわかってきたかなぁ?w


ところで、長い文字列のやつ、左に寄ってるんが気になるんですけどー
これは、flexboxとは違う話になるのですが、いつも躓くとこなので、ここに書いときます

<ポイント>
 本人のDIVのstyleに追加
  text-align:center;     テキストをセンタリングします

<div style="display:flex; border:solid 1px #008000;align-items: center;">
    <div style="text-align:center;display:flex; justify-content: center; align-items: center; background-color:#ff8888; width:100px; height:50px; margin-left:10px;"></div>
    <div style="text-align:center;display:flex; justify-content: center; align-items: center; background-color:#88ff88; width:100px; height:50px; margin-left:10px;">臨兵闘者</div>
    <div style="text-align:center;display:flex; justify-content: center; align-items: center; background-color:#8888ff; width:100px; height:50px; margin-left:10px;">臨兵闘者皆陣烈在前</div>
</div>


臨兵闘者
臨兵闘者皆陣烈在前



意図的に改行を入れたら、もっと自分のイメージに近づきました^^

<div style="display:flex; border:solid 1px #008000;align-items: center;">
    <div style="text-align:center;display:flex; justify-content: center; align-items: center; background-color:#ff8888; width:100px; height:50px; margin-left:10px;"></div>
    <div style="text-align:center;display:flex; justify-content: center; align-items: center; background-color:#88ff88; width:100px; height:50px; margin-left:10px;">臨兵闘者</div>
    <div style="text-align:center;display:flex; justify-content: center; align-items: center; background-color:#8888ff; width:100px; height:50px; margin-left:10px;">臨兵闘者<BR>皆陣烈在前</div>
</div>


臨兵闘者
臨兵闘者
皆陣烈在前



次、折返しについて書き留めておこうと、DIVをたくさん並べてみました
紛らわしいので、テキストのセンタリングは無しね。

<div style="display:flex; border:solid 1px #008000;">
    <div style="background-color:#ff8888; width:100px; margin-left:50px;"></div>
    <div style="background-color:#88ff88; width:100px; margin-left:50px;"></div>
    <div style="background-color:#8888ff; width:100px; margin-left:50px;"></div>
    <div style="background-color:#ffaaaa; width:100px; margin-left:50px;"></div>
    <div style="background-color:#aaffaa; width:100px; margin-left:50px;"></div>
    <div style="background-color:#aaaaff; width:100px; margin-left:50px;"></div>
    <div style="background-color:#ffdddd; width:100px; margin-left:50px;"></div>
    <div style="background-color:#ddffdd; width:100px; margin-left:50px;"></div>
    <div style="background-color:#ddddff; width:300px; margin-left:50px;"></div>
</div>



あれれー?おかしいなあ~。端っこで折り返さないで、DIVのwidthを縮めて全部並べようとしてるよー。 しかも、テキストの幅きちきちまで狭めても足りないから、1個はみ出してるしー。

というわけで、折返しの指定です。

<ポイント>
 親のDIVのstyleに追加
  display:flex;    flexboxですよ宣言
  flex-wrap: wrap;  無理やり収めようとせず、折り返す

<div style="display:flex;flex-wrap: wrap;border:solid 1px #008000;">
    <div style="background-color:#ff8888; width:100px; margin-left:50px;"></div>
    <div style="background-color:#88ff88; width:100px; margin-left:50px;"></div>
    <div style="background-color:#8888ff; width:100px; margin-left:50px;"></div>
    <div style="background-color:#ffaaaa; width:100px; margin-left:50px;"></div>
    <div style="background-color:#aaffaa; width:100px; margin-left:50px;"></div>
    <div style="background-color:#aaaaff; width:100px; margin-left:50px;"></div>
    <div style="background-color:#ffdddd; width:100px; margin-left:50px;"></div>
    <div style="background-color:#ddffdd; width:100px; margin-left:50px;"></div>
    <div style="background-color:#ddddff; width:100px; margin-left:50px;"></div>
</div>




で、結局のところ、flexboxって軽くメニュー作るときに一番使うんですよね
サイズかっちり合わせたい時はabsoluteでoffsetLeft,Rightで位置決めするし…
なので、左右に分けて並べたいことが、とても多いです
方法は色々あると思いますが、今んとここれが一番、自分的にわかりやすいです


<ポイント>
 親のDIVのstyleに追加
  display:flex;    flexboxですよ宣言
  justify-content: space-between; 両端を密着させた均等配置にする

 左側の子のDIVのstyleに追加
  display:flex;    flexboxですよ宣言

 右側の子のDIVのstyleに追加
  display:flex;    flexboxですよ宣言
  justify-content: flex-end; 右寄せにする

 それぞれの孫
  それぞれの左側のmargin-left:10px;を抜きました。
  ピタっと合わせたかったんで。

<div style="display:flex; justify-content: space-between; border:solid 1px #008000;">
    <div style="display:flex;">
        <div style="background-color:#ff8888;">前ページ</div>
        <div style="background-color:#88ff88; margin-left:10px;">次ページ</div>
    </div>
    <div style="display:flex; justify-content: flex-end;">
        <div style="background-color:#ff8888;">閉じる</div>
        <div style="background-color:#88ff88; margin-left:10px;">終了</div>
    </div>
</div>


前ページ
次ページ
閉じる
終了



とりあえず、ここまで。また適当に追加するかも。