お世話になります。
以前StringGridで五十音順にソートしたいという質問を
させていただいた者です。ソートについて自分なりに勉強しました。
しかし、アドレス帳を作る場合であればListViewの方が
ごちゃごちゃにならなくてよいかと思い、最終的にはListViewを
使うことにしました。
その節はご指導本当にありがとうございました。
ただ、そのアドレス帳では、「あ・か・さ・た・・・」順で
ListView1・Listview2・・・ といったように名前の頭文字を判断して
ページをかえようと思っているのですが、どういう風にすると
うまく判断して登録できるようになるでしょうか・・・?
本当に知識不足ですみません。
よろしくお願いします。
Halbow です。
具体的にやってみましょう。以下のようなテキストデータをメモ帳かテキストエディタにコピペして、'c:\テスト住所.cvs' として保存してください。
さとうくにお,佐藤邦夫,佐藤住所,佐藤郵便番号,佐藤電話
あいだいちろう,愛田一郎,東京都杉並区XXXX,112-9876,03-4499-3333
えのきたけお,榎木武雄,榎木住所,榎木郵便番号,榎木電話
すずきえみ,鈴木絵美,鈴木住所,鈴木郵便番号,鈴木電話
かめだじろう,亀田次郎,亀田住所,亀田郵便番号,亀田電話
さとうさちこ,佐藤佐知子,佐藤住所,佐藤郵便番号,佐藤電話
たなかかくえい,田中角栄,田中住所,田中郵便番号,田中電話
しもだくみこ,下田久美子,下田住所,下田郵便番号,下田電話
そして、Form1 にやや幅広の Memo1 と ListView1 と Button1 を置いて以下のようにします。
type
TForm1 = class(TForm)
Memo1: TMemo;
Button1: TButton;
ListView1: TListView;
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure Button1Click(Sender: TObject);
private
{ Private 宣言 }
public
Data:TStringList;
procedure DispALine(s:string);
end;
var
Form1: TForm1;
implementation
{$R *.DFM}
procedure TForm1.FormCreate(Sender: TObject);
var
NewColumn:TListColumn;
begin
ListView1.ViewStyle := vsReport;
NewColumn := ListView1.Columns.Add;
NewColumn.Width := 100;
NewColumn.Caption := '名 前';
NewColumn := ListView1.Columns.Add;
NewColumn.Width := 100;
NewColumn.Caption := 'よみがな';
NewColumn := ListView1.Columns.Add;
NewColumn.Width := 100;
NewColumn.Caption := '住 所';
NewColumn := ListView1.Columns.Add;
NewColumn.Width := 100;
NewColumn.Caption := '郵便番号';
NewColumn := ListView1.Columns.Add;
NewColumn.Width := 100;
NewColumn.Caption := '電話番号';
Data := TStringList.Create;
Data.LoadFromFile('c:\テスト住所.cvs');
Data.Sort; // ソートしておく
Memo1.Lines.Assign(Data);
end;
procedure TForm1.FormDestroy(Sender: TObject);
begin
Data.Free;
end;
function GetHiaraganaCode(Hiragana:string):Word;
begin
result := Ord(Hiragana[1]) shl 8 + Ord(Hiragana[2]);
end;
procedure TForm1.DispALine(s: string);
var
SL:TStringList;
LI:TListItem;
begin
SL := TStringList.Create;
try
SL.CommaText := s;
LI := ListView1.Items.Add;
LI.Caption := SL[1];
LI.SubItems.Add(SL[0]);
LI.SubItems.Add(SL[2]);
LI.SubItems.Add(SL[3]);
LI.SubItems.Add(SL[4]);
finally
SL.Free;
end;
end;
procedure TForm1.Button1Click(Sender: TObject);
var
i:integer;
Code:Word;
begin
// Shift-JIS の文字コード サ行 → 'さ' = $82B3 〜 'ぞ' = $82BC
ListView1.Items.Clear;
for i := 0 to Data.Count-1 do begin
Code := GetHiaraganaCode(Copy(Data[i],1,2));
if (Code>=$82B3) and (Code<=$82BC) then DispALine(Data[i]);
end;
end;
end.
これを実行すると、Memo1 に先ほど保存したデータが表示されます。次に、Button1 を押すと、ListView1 に サ行 だけのデータが表示されます。
> ただ、そのアドレス帳では、「あ・か・さ・た・・・」順で
> ListView1・Listview2・・・ といったように名前の頭文字を判断して
> ページをかえようと思っているのですが、どういう風にすると
> うまく判断して登録できるようになるでしょうか・・・?
データは表示とは分離して管理します。上の例では、データは Data という TStringList で保持しています。今回のような場合は、TListView は一つだけにして、TTabControl を使って、ア行、カ行・・・としてタブを選択したとき、上の例の Button1Click と同じような論理で ListView にデータを表示するとよいです。
丁寧なご回答本当にありがとうございました。
一人で感激してしまいました(^□^)
この場合、データをMemo1にロードせずに直接ListViewに表示することはできますか?
アドレス帳は画面上でユーザーに登録してもらい、それをIniFileに保存してそこから表示するようにしたいと考えていたのですが・・・。
いかがでしょうか?
Halbow です。
> この場合、データをMemo1にロードせずに直接ListViewに表示することはできますか?
Memo1 にはロードしていません。「表示している」だけです。例の Button1Click のコードをちょっと変更するだけで全データを表示できます。考えてみてください。
> IniFileに保存してそこから表示するようにしたいと考えていたのですが・・・。
何度もいいますが、GUI による「データの表示」 と 「データの保持」は分離すべきです。上の例では、TStringList のインスタンスである Data に保持しています。データの追加・削除などの変更があった場合は、Data の内容を変更し、それを表示に反映するとよいでしょう。IniFile は住所録の保存には向いていないようにおもいます。例のとおり、コンマ区切りのテキストにすると一般の宛名書きソフトやエクセルにも読み込むことができて、便利です。
とにかく骨組みはできましたので、あとはいろいろと考えて便利にしてゆくことです。その過程でまた分からないことがあったら、個別に質問するとよいです。
本当に何度もありがとうございます。
自分できちんと整理して、考えてみます!
ご指導・ご回答本当にありがとうございました。
ツイート | ![]() |