mogmo .NET

C#/XAML/VB6たまにC++についてメモ程度に書いていく。あくまで自分用。責任は取れません。

取扱説明書に使うフォントを選定した

うちの会社では取扱説明書の作成も開発者の業務なので,
毎度製品をリリースするたびに取扱説明書を作成しなければなりません。

そこで読みやすいフォントについて調べてみたので投稿します。
フォントの詳しい説明はデザイン関係の書籍やデザイン専門のサイト様に超わかりやすく書いてあるのでここでは割愛します。
※もぐもは非デザイナーです。使い方間違っていたら教えて下さい。

フォント選定で使用した基準

  • 太字,斜体に対応していること
  • Windows 8.1以降の環境で対応可能なこと

ゴシック体

主に見出しや図中の文字に使用しています。
また,目立たせたい箇所にはゴシック体を使うのが望ましいでしょう。
Wordで游ゴシックやメイリオを使う際は段落 - 間隔の設定を調整してください。
でないと行間隔が空きすぎて逆に見づらいです。(´・ω・`)

おすすめフォント

明朝体

長文を読ませる場合,明朝体のほうがゴシック体よりも適しています。
説明書中の本文のフォントはすべて明朝体ベースにしました。

おすすめフォント

サンセリフ

使い方はゴシック体と一緒。
"セリフ(字の端にあるやつ)がない" = サンセリフ

おすすめフォント

  • Segoe UI
  • Calibri ※Windowsのみ,メイリオ等字面の大きいフォントとの相性は✕

セリフ体

使い方は明朝体と一緒。

おすすめフォント

書籍

おすすめの書籍を紹介しておきます。

ではまた。

コードを書くときに気を付けていること・気をつけてほしいこと

最初のうちはこんなことに気を付けながら書いてほしいなぁ,気を付けたらいいと思うなって事項のまとめ。

今日のテーマの目次です。

では始めて行きましょう(`・ω・´)

記述ルール

命名記法

言語によって大まかなルールが決まっているので,それに合わせると良い。

記法 説明
PascalCase すべての単語の先頭が大文字 DeleteText(), CreateText()
camelCase 最初が小文字、2語目以降の先頭が大文字 csvFile, decimalLabel
snace_case アンダーバー区切り is_numeric, str_decimal
CONSTANT_CASE すべて大文字のアンダーバー区切り IDC_EDIT_DECIMAL, CONST_VALUE

※2020/4/16 @garamloverのご指摘があり,PascalCaseとcamelCaseの説明が逆だったので修正しました。

区切りの書き方

カンマ区切りなのかカンマスペース区切りなのか。
カンマスペースを用いる方が多いように思っています。

void Test1(int a, int b); // カンマスペース
void Test2(int a,int b); // カンマ

タブ

タブキーを押したとき,空白で埋めるかタブで埋めるかの違い。
VisualStudioの場合,設定はメニューの"ツール">"オプション"をクリックして
画面を開き,"テキストエディター"のタブをクリックすると,各言語の設定を変更することができる。
私は4つスペース埋めが好きです。
f:id:mogmo811:20200415171210p:plain

コメント

記法

自分は" // hogehoge" という書き方をします。
時と場合によってはtabで調整することもあります。
ですがtabは等幅フォントを使っていないエディタで見たとき悲惨なことになりますので,あまり使わないようにしています。

int a; // スペース//スペースコメント
int b;// //スペースコメント
int c;//コメント
コメントの内容

不要なコメント,間違ったコメントは悪なので後回しにせずすぐ削除・修正する癖をつけましょう。

行間

行間にも意味があると思って書くこと。
行間は文章でいう段落,もしくはグルーピングの方法だと思ってほしい。

例えば下のように2個の条件分岐も行間がないとぱっと見1つの条件分岐に見えてしまう。

int a = 10;
if(a < 10)
{
    a = 0;
}
else if(a > 50)
{
    a = 999;
}
if(a ==0)
{
   return a;
}
else if(a > 100)
{
    // hogehoge
}
// 続く...

ほかにもヘッダファイルで関数のグルーピングが適当だと,恐ろしく読みづらい。
かなり適当な例ですが。。。悪い例。

// C++です
int ConvertToValue(std::string text);
std:string ConvertToText(int value);
void Convert();

void LoadText();

void LoadValue();

int Mul(int a, int b);

void ClearBuffer();
int Add(int a, in b);
int Sub(int a, int b);

私が書き直すとこんな感じかな。
メイン処理(っぽそうな関数名)と,変換処理関数,演算用関数でグルーピングしました。

void Convert();
void LoadText();
void LoadValue();
void ClearBuffer();

int ConvertToValue(std::string text);
std:string ConvertToText(int value);

int Add(int a, in b);
int Sub(int a, int b);
int Mul(int a, int b);

VisualStudioならオプション設定を有効活用しよう

メニューの"ツール">"オプション"をクリックして画面を開き,
テキストエディターのタブをクリックすると,各言語のコーディングルールが設定できる。
※ローカルのVSのみに反映するので他の人のVSには影響しない。設定を共有するにはプロジェクトごとにEditorConfigを設定する必要があるがここでは言及しない

言語によって設定できる内容は微妙に違うが,

  • タブの空白埋めかタブ埋め
  • switch文のcaseの位置
  • {}の位置(私はTest2派)
void Test1() {
    //...
}
void Test2()
{
    // ...
}

などなど細かに決められる。

これを決めておけば,「ドキュメントのフォーマット」機能を実行したとき,設定に沿ってフォーマットしてくれる。
ショートカットキーのデフォルトは Ctrl+K, Ctrl+D

コードについて

基本C#XAMLを書いている私ですが,C++を使う機会があったのでC++の話も交えて書きます。

アクセス権限

public, private, protected, etc...のことです。

自身のクラスから参照する必要があるのかを検討してアクセス修飾子を選定しましょう。
publicはどこからでもアクセスできて危険です。
まずはprivateで考え,外部からのアクセスが必要なものならその参照範囲を想定してprotected や internal,publicなどを使用する...といった風に考えると使いやすいかなぁと思います。
この辺はクラスをいくつも設計したり,継承を使ったりすると特に気にして設計しなければなりません。
C++参考:アクセス修飾子
C#参考:アクセス修飾子 - C# プログラミング ガイド | Microsoft Docs

cppファイルとヘッダファイル [C++]

ヘッダファイルとcppファイルの記述順は一致していてほしいものです。

ヘッダファイルの記述がぐちゃぐちゃだったり,不要なコメント,不適切なコメント,実際には使っていない関数や変数が乱立していると一目見て読む気が失せてしまいます。

  • 常に整理しながら書くこと
  • 命名時に十分に検討すること
  • こまめに確認・修正を繰り返す

という癖をつけておきましょう。

また, ヘッダファイルにusing std;は記述しないようにしている。
理由はhファイルを使う人がusing stdに気づかない恐れがあるから。
また,略さないで書いたほうが読み手に伝わりやすいと思うので,usingせず素直にstd::filesystemとかstd::wstringと書いています。

インクルードファイル [C++]

以下のサイトを参考にしてください。
インクルードファイルとは:
https://wa3.i-3-i.info/word12024.html
インクルードファイルの指定方法:
Oracle Solaris Studio 12.3 Information Library (日本語)

文字列 [C++]

文字列の型いっぱいあるんですよね...
この辺はまた次回書こうかな。

終わりに

最初のうちに気を付けてほしいことを書きました。
きれいに書くことはあとで保守する自分のためにもなりますし,
担当が変わっても保守しやすいプログラムになりますので記述には注意しましょう。

ではまた。(`・ω・´)ノ"

もぐも

VBA|基本①データ型,繰り返し,配列など 

こんにちは。もぐもです。
VBAを基礎から見直す機会があったので投稿します。

そもそもVBAってなに

  • Visual Basic for Applicationsの略
  • MicroSoftのOffice製品の一部(ExcelやWordなど)で利用可能なプログラミング言語
  • プログラムすることで複雑な処理を自動化できますよって機能

環境を整える

エクエルのオプションから開発タブを表示する設定に変更する。
Visual BasicあいこんからVisual Basic Editorを表示する。
挿入>標準モジュールに処理を書いていく

基本の文法

プロシージャ

関数のこと。
Sub~End Subで囲んだ内容が一つの処理として認識される。
プロシージャ名は日本語も使えるが,必ず文字始まりでなければいけない。

Sub プロシージャ名()
End Sub
プロシージャ内部の書き方
Sub Test()
    '一行ずつ処理を書く
    Range("A1").Value = 100
    Range("A2").Value = 200
    
    '一行に複数の処理を書く場合は :(コロン) をつかう
    Range("A1").Value = 100: Range("A2").Value = 200
    
    '複数行に分けるときは _(アンダーバー)をつかう
    Range("A1").Value = 100
    Range("A2").Value _
        = 200
End Sub

変数

Sub Test2()
    '変数の宣言 Dimを先頭に書くことで変数を宣言できる
    Dim name
    Dim age
    Dim level
    
    '格納するデータ型がバラバラでも,カンマで1行にまとめて宣言することもできる
    'Dim name, age, level
    
    '変数の格納: =(イコール)を用いて値を格納する
    name = "もぐも" '文字列は "(ダブルクォーテーション) で囲む
    age = 28
    level = 1
    
    '変数の値をセルに表示する
    Range("A1").Value = name
    Range("A2").Value = age
    Range("A3").Value = level
End Sub
データ型

公式文書:
データ型の概要 | Microsoft Docs

データ型の種類は以下の表のとおり。

データ型 バイト数 値の範囲
Boolean 2バイト True/False
Byte 1バイト 0 ~ 255
Collection 不明 不明
Currency(通貨型) 8バイト -922,337,203,685,477.5808 ~ 922,337,203,685,477.5807
Date 8バイト 100 年 1 月 1 日 から 9999 年 12 月 31 日
Decimal 14バイト 公式サイト参照
Dictionary 不明 不明
Double 8バイト ±double max ~ ±double min
Integer 2バイト -32,768 ~ 32,767
Long 4バイト -2,147,483,648 ~ 2,147,483,647
LongLong 8バイト -9,223,372,036,854,775,808 ~ 9,223,372,036,854,775,807
Object 4バイト 任意
Single 4バイト ±3.402823E+38 から ±-1.401298E-45
String(可変長) 10バイト+文字列の長さ 0~約 20 億
String(固定長) 指定した文字列の長さ 1 ~ 約 65,400
Variant(数値型) 16バイト 最大でDoubleの範囲までの任意の数値
Variant(文字列型) 22 バイト + 文字列長 (64 ビット システムでは 24 バイト) String(可変長)と同じ範囲

※ LongLong: 64ビットプラットフォームでのみ有効
※LongPtr,Typeは割愛した

数値型の場合,整数型はByte,Integer,Longがある。(64ビットではLongLongも利用可能)
浮動小数点の場合はSingle,Doubleがある。しかしこの2つのデータ型には有効桁数が決まっており計算を行えば桁落ちが発生したり,表現できない値が出てくる。正確な計算を強いられる場面ではCurrencyを用いると良い。

データ型を指定して変数を宣言

As を用いて変数のデータ型を指定できる。

Sub Test3()
    '変数の型を指定して宣言: As を用いる
    Dim name As String
    Dim age As Byte
    Dim level As Integer
        
    'カンマで1行にまとめて宣言する場合
    'Dim name As String, age As Byte, level As Integer
End Sub
日付型

#で囲むか文字列として指定する

Dim x As Date

x = "2020年10月12日"
x = #20201012日#
x = #2020/10/12#
x = #12/10/2020#
x = #12:26:39 AM#

演算子

算術演算子
Sub Test()
    Dim x As Integer
    Dim y As Single
    
    x = 5 + 2 '足し算 = 7
    x = 5 - 2 '引き算 = 3
    x = 5 * 2 '掛け算 = 10
    y = 5 / 2 '割り算 = 2.5
    x = 5 \ 2 '割り算の商 = 2
    x = 5 Mod 2 '割り算の余り = 1
    x = 5 ^ 2 'べき乗 = 25
End Sub
比較演算子

結果はBoolean型で返ってくる。
C++C#と違うのは等しい,等しくないの演算子の書き方。

Sub Test()
    Dim result As Boolean
    result = 8 < 5  'より小さい False
    result = 3 <= 5 '以下 True
    result = 8 > 5  'より大きい True
    result = 3 >= 8 '以上 False
    result = 3 = 8  '等しい False
    result = 3 <> 8 '等しくない True
    
    Range("A1").Value = 10 > 20 'セルA1にFALSEが表示される
End Sub
論理演算子
Sub Test()
    Dim result As Boolean
    '論理積 And
    result = (3 < 5) And (2 < 5) '=True
    '論理和 Or
    result = (3 > 5) Or (2 > 5) '=Flase
    '論理否定 Not
    result = Not (3 < 5) '=False
End Sub

文字の結合

& と +が使えるが,&のほうがケアレスミスが減るかも。

Sub Test()
    Dim hello As String
    Dim name As String
    Dim a As Integer
    Dim b As Integer
    
    hello = "こんにちは"
    name = "もぐも"
    a = 10
    b = 12
    
    Range("A1").Value = hello & name '=こんにちはもぐも
    Range("A2").Value = hello & a '=こんにちは10
    Range("A3").Value = a & hello '=10こんにちは
    Range("A4").Value = a & b '=1012
    
    Range("A5").Value = hello + name 'こんにちはもぐも
    'Range("A6").Value = hello + a 'Error: 型が一致しません
    'Range("A7").Value = a + hello 'Error: 型が一致しません
    Range("A8").Value = a + b '=22
End Sub

オブジェクト

  • データ型の1つ
  • ブックやシート,セルなどVBAで何か操作をしようとする対象となるもの
  • 値の格納にはSetを先頭に書かなければならない
Sub Test()
    'オブジェクト: VBAで何か操作しようとする対象となるもの
    
    'オブジェクトの宣言
    Dim app As Application 'アプリケーション
    Dim book As Workbook 'ブック
    Dim sheet As Worksheet 'シート
    Dim cell As Range 'セル
    Dim books As Workbooks '開いている全てのブック
    Dim sheets As Worksheets 'ブックに含まれる全てのワークシート
    
    '値を格納する: Setを使って格納すること
    Set cell = Range("A1")
    cell.Value = "cellにA1のセルを格納しました"

    'オブジェクトのプロパティやメソッドは.(ドット)を用いて利用することが可能
    cell.Value = "プロパティを変更" 'プロパティ値を変更
    
    Dim test As String 'プロパティ値を取得
    test = cell.Value
    
    cell.Delete 'メソッドを利用
End Sub

条件分岐

If と Select(C++C#ではswitchに相当する) が使える。

Sub test()
    Dim cell As Range
    Set cell = Range("A1")
    
    '条件分岐①: If 条件式 Then ~ ElseIf 条件式 Then ~ Else ~ End If
    If (cell.Value = "") Then '空白なら
        cell.Value = "あ"
    ElseIf (cell.Value = "あ") Then
        cell.Value = "い"
    Else
        cell.Value = "う"
    End If
    
    '条件分岐②-1: Select
    Select Case cell.Value
        Case ""
            cell.Value = "あ"
        Case "あ"
            cell.Value = "い"
        Case Else
            cell.Value = "う"
    End Select
    
    '条件分岐②-2: 比較演算子の省略
    Dim x As Integer
    x = 10
    
    Select Case x
        Case Is > 20
            cell.Value = "20より大きい"
        Case Is > 5
            cell.Value = "5より大きい"
        Case Else
            cell.Value = "5以下の値です"
    End Select
End Sub

繰り返し

Sub test()
    Dim sum As Integer
    
    '繰り返し①: Do While ... Loop
    Dim sum As Integer
    Dim x As Integer
    sum = 0
    x = 1

    Do While x <= 10 '条件式 xが10以下 がTrueなら繰り返す
        sum = sum + x
        x = x + 1
    Loop
    
    '繰り返し②: Do Until ... Loop
    sum = 0
    x = 1
    Do Until x > 10 '条件式 xが10より大きい がFalseの場合は繰り返す
        sum = sum + x
        x = x + 1
    Loop
    
    '繰り返し③: Do ... Loop While
    '処理を行った後に条件式の判定を行う。つまり必ず1度は繰り返し処理を行う。
    sum = 0
    x = 1
    Do
        sum = sum + x
        x = x + 1
    Loop While x <= 10 '条件式 xが10以下 がTrueなら繰り返す
        
    '繰り返し④: For a To b ~ Next
    sum = 0
    For x = 1 To 10
        sum = sum + x
    Next i
    
    Range("A1").Value = sum
End Sub

配列

配列の宣言は

Dim 変数名(要素数-1) As データ型

と行う。
変数名(3 To 6)と宣言する方法もあるが,保守しやすいとは思わないので割愛する。

サンプル

Sub Test()
    '配列の宣言: 配列数10個
    Dim collection(9) As Integer
    
    collection(0) = 1
    collection(1) = 2
    collection(2) = 3
    collection(3) = 4
    collection(4) = 5
    collection(5) = 6
    collection(6) = 7
    collection(7) = 8
    collection(8) = 9
    collection(9) = 10
    'collection(10) = 11 '要素数を超えたらエラーとなる
    
    Dim i As Integer
    For i = 0 To 9
        Range("A1").Value = collection(i)
    Next i
End Sub

参考

Excel VBA入門 ~基本的な使い方から高度な利用方法までサンプルを使って解説します~
こちらのサイトをもとに学習しています。

ではまた(`・ω・´)
もぐも

リモートコードレビューを試した - 失敗

もぐもです。試験的に在宅勤務が開始されました。
そこで,りもーど環境でコードビューを試してみようとしたところ問題点だらけ...
次回コードレビューを行うときはこの問題点を解決しなければならない。

試そうとしたこと

  • VS 2019 の Live Share 機能を使ってリモートコードレビューをしようとした。
  • ビデオ通話はGoogleのハングアウトかmeetしか使えない

問題点

  • ハングアウト,Meetでマイク,ビデオ環境をテストしていなかった
  • そもそもVS2019をインストールしてない人がいた
  • Live Shareは問題なく開始できたが,文章の途中でテキストの色分けがint や void 以外すべてコメント色になってしまい読みづらさMAX
  • MFCアプリケーションのコードレビューを行ったが実際の動作を確認したい → exeはファイル転送サービスを利用して受け渡しするしか思いつかなかった。泥臭い。

C++ | テンプレートの実装はヘッダファイルに書かなければならない

f:id:mogmo811:20200402170734j:plain

こんにちは。もぐもです。
久しぶりにC++を触っています。

さて,C++MFCアプリケーションを実装している際に,以下のようなエラーが出て四苦八苦しました。

LNK2019 未解決の外部シンボル "public: static int __cdecl Calc::Add(int,int)" (?Add@?$Calc@H@@SAHHH@Z) が関数 "private: void __thiscall CMFCApplication1Dlg::Adding(void)" (?Adding@CMFCApplication1Dlg@@AAEXXZ) で参照されました。

結論から言うと

原因を調べた結果,分割コンパイルによる実体の不在のためにおこるリンクエラーのようです。
対策は,テンプレートクラスや関数の実装をヘッダファイルで行うことでコンパイルが通ります。

原因について

サンプルコード

エラーの出るサンプルコードを記載します。
プロジェクトはMFCアプリケーションで作成しました。
MFCApplication1Dlgクラス の Adding関数 の中で Calcクラス の Add関数 を呼ぶコードになっている。

/* Calc.h */

#pragma once
template<class T>
class Calc
{
public:
    static int Add(T a, T b);
};
/* Calc.cpp */

#include "pch.h"
#include "Calc.h"

template<class T>
inline int Calc<T>::Add(T a, T b)
{
    return a + b;
}
/* MFCApplication1Dlg.cpp */

#include "Calc.h"

// ----- 省略 -----

void CMFCApplication1Dlg::Adding()
{
	int sum = Calc<int>::Add(10, 20);
}

ビルドするとどうなるか

ビルド出力は以下のようになった。

1>------ すべてのリビルド開始: プロジェクト:MFCApplication1, 構成: Debug Win32 ------
1>pch.cpp
1>Calc.cpp
1>MFCApplication1.cpp
1>MFCApplication1Dlg.cpp
1>コードを生成中...
1>MFCApplication1Dlg.obj : error LNK2019: 未解決の外部シンボル "public: static int __cdecl Calc::Add(int,int)" (?Add@?$Calc@H@@SAHHH@Z) が関数 "private: void __thiscall CMFCApplication1Dlg::Adding(void)" (?Adding@CMFCApplication1Dlg@@AAEXXZ) で参照されました。
1>C:\Users\***\repos\MFCApplication1\Debug\MFCApplication1.exe : fatal error LNK1120: 1 件の未解決の外部参照
1>プロジェクト "MFCApplication1.vcxproj" のビルドが終了しました -- 失敗。
========== すべてリビルド: 0 正常終了、1 失敗、0 スキップ ==========

Calc.cppコンパイル時,Add関数を使っている箇所が見当たらない→Add関数のテンプレートの実体化が行われません。
もっと言えば,今回のコードの場合がCalc自体がテンプレートクラスなのですが,Calcクラスを使用している箇所が見当たらないため,クラスの実体化も行われません。
結果,実体化していない状態でCalc.objファイルが生成されます。

次に,MFCApplication1Dlg.cppのコンパイルです。
MFCApplication1Dlg.cppではAdding関数でCalcクラスのAdd関数を使用していますが,Calc.hに宣言されているので実体の有無にかかわらずコンパイルが通り,MFCApplication1Dlg.objファイルが生成されます。

さて,これでコードを生成しようとすると,MFCApplication1Dlg.objちゃんはCalcクラスのAdd関数をCalc.objから探し出そうとしますが,Calc.objは分割コンパイル時に実体化が行われていないのでint型のAdd関数は存在しません。
よって,未解決の外部シンボルエラーが発生するという流れでビルドエラーになります。

正しい実装方法

インライン関数でヘッダファイルに実装します。
Calc.cppは空でOKです。

/* Calc.h */

#pragma once
template<class T>
class Calc
{
public:
    static int Add(T a, T b);
};

template<class T>
inline int Calc<T>::Add(T a, T b)
{
    return 0;
}

参考

以下ブログを参考にしました。
テンプレートの実装をヘッダに書かなければならない理由 - (void*)Pないと

せっかくなので自分の言葉で書いてみました。
間違い等あれば連絡ください。

ではまた。
もぐも(`・ω・´)🍙

Git|SSHで接続できなくなった

新しい環境でリモートリポジトリをクローン出来なくなったのでさあ困った。ってなったときに対処した方法。

結果

lipoyang.hatenablog.com
を見ていると,ユーザー設定がおかしそうだいうことが分かった。
どうやらサーバーが受け取るユーザIDの設定が違うので,接続できないという状況。。。
userhostsの中身を修正したら無事接続できた。

紆余曲折

一応メモっとく。

  • コマンドプロンプトSSH接続→できる
  • SourceTreeオプション>認証を確認→本来ここにアカウント設定が確認できない
  • パスワードを保存している場所を探し出す

メイン画面が起動する前にダイアログを表示する

メイン画面を起動する前に独自のダイアログを表示したくて調べた。
ログイン画面を表示する時なんかが多いかもしれない。

問題点

App.xaml.csでMainWindowを表示する前にダイアログを表示するコードを書いて実行すると,ダイアログを閉じたらアプリケーションが終了してしまい,MainWindowが開きません。
この対策についてメモしておく。

対策1 ShutdownModeを設定する

アプリケーションの実行停止モードを設定してダイアログをとじてもアプリが終了しないようにしてしまう方法。

ShutdownMode 説明
OnLastWindowClose[規定値] アプリケーションの最後のウィンドウを閉じると暗黙的に終了
OnMainWindowClose Application.MainWindowプロパティに割り当てられているウィンドウが閉じた時暗黙的に終了
OnExplicitShutdown 手動でShutdown();するまで終了しない

ShutdownMode公式ドキュメント→Application.ShutdownMode プロパティ (System.Windows) | Microsoft Docs

事前にMainWindowプロパティにメイン画面を登録できない & 元の値に戻さなければならない都合が合って以下のような書き方になっているが,参考までに載せておく。

var dialog = new SampleDialog();
var temp = Current.ShutdownMode;
Current.ShutdownMode = ShutdownMode.OnExplicitShutdown; // memo: 一時的な変更
if (dialog.ShowDialog() != true)
{
	this.Shutdown();
}
Current.ShutdownMode = temp; // memo: 元に戻す


ではまた。
もぐも