https://wiki.freepascal.org/index.php?title=Special:NewPages&feed=atom&hideredirs=1&limit=50&offset=&namespace=0&username=&tagfilter=&size-mode=max&size=0Lazarus wiki - New pages [en]2024-03-29T00:52:36ZFrom Lazarus wikiMediaWiki 1.35.6https://wiki.freepascal.org/SQLdb_Tutorial4/jaSQLdb Tutorial4/ja2024-03-27T15:34:22Z<p>Ariben: </p>
<hr />
<div>{{SQLdb Tutorial4}}<br />
<br />
{{Infobox databases/ja}}<br />
== Introduction ==<br />
This tutorial is an attempt to demonstrate the use of [[Data module|Lazarus Data Modules]] to isolate the data access components of a project from the program logic associated with the access. Such isolation makes program maintenance and debugging easier. <br />
<br />
The tutorial was developed using Windows 7 and SQLite3 as the database, with Lazarus 1.0.8 with FPC 2.6.2; however it should work with earlier versions. Similarly, other DBMS and Operating Systems should require minimal change, if any.<br />
<br />
== Why use datamodules? ==<br />
Simple - after following the Lazarus Tutorials:<br />
* [[SQLdb Tutorial0]]<br />
* [[SQLdb Tutorial1]]<br />
* [[SQLdb Tutorial2]]<br />
* [[SQLdb Tutorial3]]<br />
developing a 'real' application becomes harder. 'Form1' grows to an exponential size handling the different Events and Database Queries. <br />
<br />
Isolating each table access into a single datamodule makes debugging and maintenance so much easier. An application may have any number of datamodules - a small application with just one or 2 tables can probably suffice with just one Datamodule - a larger application could probably benefit from having a data module for each table or view.<br />
<br />
The sample shown here uses just 2 tables with simple queries, but it can be expanded to include more options with each table. <br />
<br />
== Getting started ==<br />
In the Lazarus IDE, create a new Application and then click File --> New --> Data Module<br />
<br />
[[file:newDM.jpg]]<br />
<br />
You will be presented with a window as if you selected 'New Form': <br />
<br />
[[file:dm1.jpg]]<br />
<br />
The difference is this window/form will only accept non-visual components. In fact, look at your Component Palette: it has been greatly reduced to only allow selection of ONLY non-visual components.<br />
<br />
<br />
== Everyone has their own way ==<br />
Your use of data modules will vary to suit your own needs. but as an example, I have at least 2 data modules:<br />
<br />
Unit: DataModule1 <br />
On this module I 'drop' a ''T*Connection'' and a ''TSQLTransaction''.<br />
<br />
[[file:conn.jpg]]<br />
<br />
DataModule1 is used as the connection for all queries.<br />
<br />
I then create a DataModuleN for each table or view.<br />
<br />
[[file:dm2.jpg]]<br />
<br />
Each DataModuleN will need to have the DataModule1 unit (unit2 in this example) added to the USES clause to connect to the database.<br />
<br />
From here everything is the same as stated in [[SQLdb Tutorial1]]. The components are connected in the same way and access is identical.<br />
<br />
==More uses of data modules==<br />
=== Additional components ===<br />
In this example, DataModule1 had nothing more than a Connection and Transaction, but in a 'real' application, this container would typically also hold global non-visual components to be used by the application. <br />
<br />
For example, Load and Save INI settings, ''TOpenDialog'', ''TSaveDialog'', etc. The concept here is to isolate data access from the business logic of an application. A change in data source for any application is never a minimal task, but having the datasources isolated will make the change much easier.<br />
<br />
=== Debugging ===<br />
Debugging a program is also a difficult task. By separating data access and business logic, the code to be viewed is halved. Data access and business logic can be tested separately to at least halve the problem.<br />
<br />
The importance of the ''DataModule'' will become even more obvious when developing other applications using the same database and tables. The data module can of course be reused in the new application.</div>Aribenhttps://wiki.freepascal.org/SQLdb_Tutorial3/jaSQLdb Tutorial3/ja2024-03-27T15:33:12Z<p>Ariben: /* See also */</p>
<hr />
<div>{{SQLdb Tutorial3}}<br />
<br />
{{Infobox databases/ja}}<br />
== 概要 ==<br />
このチュートリアルでは、次の方法を学ぶ<br />
* ログインフォームの使用など、アプリケーションを複数のデータベースに適したものにする<br />
* データベース データを (データベース コントロールではなく) 通常のコントロールに取得する<br />
* コントロールからデータを取得してデータベースに戻す<br />
* パラメータ化されたクエリを実行する。<br />
<br />
== マルチデータベースのサポート ==<br />
任意のデータベースとログイン フォームを使用して、SQLDB がサポートする複数の異なるデータベース サーバー/組み込みライブラリをサポートできる。<br />
<br />
利点:<br />
* ユーザー/プログラマは、任意の sqldb t*connection を動的に使用できるため、データベースを選択できる。<br />
<br />
短所:<br />
* より複雑な SQL をさらに調整する必要がある可能性がある。 各データベースには独自の方言がある。 もちろん、データベース固有の SQL を呼び出すことも可能だが、これはメンテナンスの問題に発展する可能性がある。<br />
* T*connection 固有のプロパティ (Firebird 方言を設定するための ''TIBConnection.Dialect'' など) は使用できない。<br />
<br />
マルチデータベース サポートを使用するには、''TIBConnection'' などの特定の T*Connection の代わりに、''TSQLConnector'' (''TSQLConnection'' ではない) を使用する。これにより、(プログラムの実行中に) 特定の T*Connection が動的に選択される。 <br />
''ConnectorType''プロパティに基づいてT*Connectionを使用する。:<br />
<br />
<syntaxhighlight lang=pascal><br />
uses<br />
...<br />
var<br />
Conn: TSQLConnector;<br />
begin<br />
Conn:=TSQLConnector.Create(nil);<br />
try<br />
// ...実際のコネクタのタイプはこのプロパティによって決まる。<br />
// ChosenConfig.DBType 文字列が一致することを確認する<br />
// コネクタのタイプ (例:<br />
// そのコネクタの T*ConnectionDef.TypeName 。<br />
Conn.ConnectorType:=ChosenConfig.DBType;<br />
// 残りは通常通り:<br />
Conn.HostName:='DBSERVER';<br />
Conn.DatabaseName:='bigdatabase.fdb';<br />
Conn.UserName:='SYSDBA';<br />
Conn.Password:='masterkey';<br />
try<br />
Conn.Open;<br />
</syntaxhighlight><br />
<br />
== ログインフォーム ==<br />
[[SQLdb Tutorial1/ja]] で説明したように、ユーザーはアプリケーションにハードコードされた資格情報を使用するのではなく、フォーム (または安全に保存されている構成ファイル) を使用してデータベースにログインする必要がある。 セキュリティ上の考慮事項に加えて、データベース サーバーの情報が変更されるたびにアプリケーションを再コンパイルしなければならないのは、あまり良い考えではない。<br />
<br />
''dbconfiggui.pas'' では、ini ファイルが存在する場合はそこからデフォルト値を取得するログイン フォームをセットアップする。 これにより、エンタープライズ展開、いくつかの詳細 (データベース サーバ、データベース名) を入力してデフォルトの接続を設定できる。 。<br />
このフォームでは、ユーザーは自分のユーザー名/パスワードを追加/編集し、次に進む前に接続をテストできる。<br />
<br />
[[File:dbloginform.png]]<br />
<br />
''TDBConnectionConfig'' クラスを持つ別の dbconfig.pas ユニットを使用して、選択した接続の詳細を保存します。 このクラスは、ini ファイルからのデフォルト設定の読み取りをサポートしています。<br />
<br />
これにより、GUI ログイン フォームなしでの使用 (例: 無人/バッチ操作の実行時) が可能になり、たとえば、Web サイトでの再利用が可能になる。<br />
<br />
この''TDBConnectionConfig''クラスはログイン フォームに''Config''プロパティとして表示されるため、メイン プログラムは設定フォームをモーダルに表示し、ユーザーによる [OK] クリックを検出して、フォーム設定を閉じる前に選択した設定を取得できる。<br />
<br />
=== 接続テストコールバック関数 ===<br />
ログイン フォームを柔軟に保つために (Zeos などの他のデータベース層で使用できる)、テスト セクションをコールバック関数として実装し、メイン プログラムで処理させる。<br />
<br />
''dbconfiggui.pas'' のログイン フォームの定義:<br />
<syntaxhighlight lang=pascal><br />
type<br />
TConnectionTestFunction = function(ChosenConfig: TDBConnectionConfig): オブジェクトのブール値。<br />
</syntaxhighlight><br />
<br />
メイン フォームは、構成フォームからのテスト リクエストを処理するために、この定義に一致する関数を実装する必要がある。<br />
<br />
コールバック関数は、構成フォームによって渡された構成オブジェクトを受け取り、それを使用して、選択されたデータベース タイプとの接続を構築する。 その後、単純にサーバーへの接続を試行する。 成功した場合は関数の結果を true に設定し、そうでない場合は結果は false のままとなる。<br />
<br />
存在しないサーバーへのデータベース接続の試行は長いタイムアウトになる可能性があるため、カーソルを砂時計アイコンに設定して待機する必要があることをユーザーに示す。<br />
<syntaxhighlight lang=pascal><br />
uses<br />
...<br />
dbconfig, dbconfiggui<br />
...<br />
procedure TForm1.FormCreate(Sender: TObject);<br />
LoginForm:=TDBConfigForm.Create(self);<br />
try<br />
// dbconfigguiのテストボタンはこのプロシージャにリンクされるだろう<br />
//ここで...これが''dbconfiggui.pas''の コールバックをConnectionTest functionにリンクさせる...<br />
LoginForm.ConnectionTestCallback:=@ConnectionTest;<br />
...<br />
function TForm1.ConnectionTest(ChosenConfig: TDBConnectionConfig): boolean;<br />
// コネクションを確かめるためにdbconfigguiの情報を使うコールバック関数<br />
// 確かめるために結果をdbconfigguiへ返す<br />
var<br />
// 通常のデータベース接続...<br />
Conn: TSQLConnector;<br />
begin<br />
result:=false;<br />
Conn:=TSQLConnector.Create(nil);<br />
Screen.Cursor:=crHourglass;<br />
try<br />
// ...このプロパティで決定される実際の接続タイプ。<br />
// ChosenConfig.DBType文字列がマッチすることを確かめること<br />
// コネクタタイプ(例えば、このコネクタにたいする<br />
// T*ConnectionDef.TypeNameをみること<br />
Conn.ConnectorType:=ChosenConfig.DBType;<br />
Conn.HostName:=ChosenConfig.DBHost;<br />
Conn.DatabaseName:=ChosenConfig.DBPath;<br />
Conn.UserName:=ChosenConfig.DBUser;<br />
Conn.Password:=ChosenConfig.DBPassword;<br />
try<br />
Conn.Open;<br />
result:=Conn.Connected;<br />
except<br />
// 結果はすでにfalse<br />
end;<br />
Conn.Close;<br />
finally<br />
Screen.Cursor:=crDefault;<br />
Conn.Free;<br />
end;<br />
end;<br />
</syntaxhighlight><br />
<br />
最後に、実際にコールバックを呼び出す ''dbconfiggui.pas'' 内のコードが [テスト] ボタンにリンクされます。 (クラッシュを避けるために) コールバック関数が割り当てられているかどうかをテストする。完全を期すために、有効な構成オブジェクトがあるかどうかもチェックし、単純にコールバック関数を呼び出す。<br />
<br />
<syntaxhighlight lang=pascal><br />
...<br />
TDBConfigForm = class(TForm)<br />
...<br />
private<br />
FConnectionTestFunction: TConnectionTestFunction;<br />
public<br />
property ConnectionTestCallback: TConnectionTestFunction write FConnectionTestFunction;<br />
...<br />
procedure TDBConfigForm.TestButtonClick(Sender: TObject);<br />
begin<br />
// 設定を持つコールバックを呼び出す、接続が<br />
// 成功したことを明らかにし、テスト結果を返す<br />
if assigned(FConnectionTestFunction) and assigned(FConnectionConfig) then<br />
if FConnectionTestFunction(FConnectionConfig) then<br />
showmessage('Connection test succeeded.')<br />
else<br />
showmessage('Connection test failed.')<br />
else<br />
showmessage('Error: connection test code has not been implemented.');<br />
end;<br />
</syntaxhighlight><br />
<br />
=== 追加・修正 ===<br />
ログインフォームの可能な追加/変更:<br />
* dbconfig のコマンド ライン引数処理を追加して適切なデフォルトをプリロードし、プログラムをバッチ スクリプトやショートカットなどで使用できるようにする。<br />
* ログインフォームに「プロファイルの選択」コンボボックスを追加する。 ini ファイル内でデータベースの種類と接続の詳細を指定する複数のプロファイルを使用する。<br />
* 1 つのデータベース タイプのみがサポートされている場合は、データベース タイプ コンボボックスを非表示にする。<br />
* 組み込みデータベースが選択されていることが確実な場合は、ユーザー名とパスワードを非表示にする。<br />
* MS SQL Server コネクタを使用したポート番号またはインスタンス名の指定のサポートを追加。<br />
* 信頼できる認証をサポートするデータベース (Firebird、MS SQL) にサポートを追加: ユーザー名/パスワードの制御を無効にする<br />
* 組み込みデータベースを選択したがファイルが存在しない場合: 確認要求を表示し、データベースを作成する<br />
* コマンドライン アプリケーション用にログイン フォームのコマンドライン/TUI バージョンを作成する(たとえば、curses ライブラリを使用)<br />
この記事やコードの更新は大歓迎する。<br />
<br />
== Getting database data into normal controls ==<br />
{{Note|Before starting this section, please make sure you have set up the sample employee database as specified in [[SQLdb Tutorial0#Requirements]]}}<br />
<br />
In previous tutorials, data-bound controls were covered: special controls such as the [[TDBGrid]] that can bind its contents to a [[TDataSource]], get updates from that source and send user edits back.<br />
<br />
It is also possible to programmatically retrieve database content and fill any kind of control (or variable) with that content. As an example, we will look at filling a stringgrid with some salary details for the sample employee database table.<br />
<br />
On the main form, let's add a [[TStringGrid]] and retrieve the data (e.g. via a procedure ''LoadSalaryGrid'' called in the ''OnCreate'' event):<br />
<syntaxhighlight lang=pascal><br />
// Load from DB<br />
try<br />
if not FConn.Connected then<br />
FConn.Open;<br />
if not FConn.Connected then<br />
begin<br />
ShowMessage('Error connecting to the database. Aborting data loading.');<br />
exit;<br />
end;<br />
<br />
// Lowest salary<br />
// Note: we would like to only retrieve 1 row, but unfortunately the SQL<br />
// used differs for various dbs. As we'll deal with db dependent SQL later<br />
// in the tutorial, we leave this for now.<br />
// MS SQL: 'select top 1 '...<br />
FQuery.SQL.Text:='select ' +<br />
' e.first_name, ' +<br />
' e.last_name, ' +<br />
' e.salary ' +<br />
'from employee e ' +<br />
'order by e.salary asc ';<br />
// ISO SQL+Firebird SQL: add<br />
//'rows 1 '; here and below... won't work on e.g. PostgreSQL though<br />
FTran.StartTransaction;<br />
FQuery.Open;<br />
SalaryGrid.Cells[1,1]:=FQuery.Fields[0].AsString; // i.e. Cells[Col,Row]<br />
SalaryGrid.Cells[2,1]:=FQuery.Fields[1].AsString;<br />
SalaryGrid.Cells[3,1]:=FQuery.Fields[2].AsString;<br />
FQuery.Close;<br />
// Always commit(retain) an opened transaction, even if only reading<br />
// this will allow updates by others to be seen when reading again<br />
FTran.Commit;<br />
...<br />
end;<br />
except<br />
on D: EDatabaseError do<br />
begin<br />
FTran.Rollback;<br />
MessageDlg('Error', 'A database error has occurred. Technical error message: ' +<br />
D.Message, mtError, [mbOK], 0);<br />
end;<br />
end;<br />
</syntaxhighlight><br />
<br />
Things to note: we catch database errors using try..except. You'll notice we forgot to roll back the transaction in case of errors - which is left as an exercise to the reader.<br />
<br />
We ''Open'' the query object, thereby asking ''FQuery'' to query the database via its ''SQL'' statement. Once this is done, we're on the first row of data. We simply assume there is data now; this is actually a programming error: it would be tidier to check for ''FQuery.EOF'' being true (or ''FQuery.RecordCount'' being >0).<br />
<br />
Next, we retrieve the data from the first row of results. If we wanted to move to the next row, we'd use ''FQuery.Next'', but that is not necessary here. We put the results in the stringgrid, giving the lowest salary in the list. A similar approach can be taken for the highest salary.<br />
<br />
== Adapting SQL for various databases ==<br />
As we noticed above, various databases support various versions of SQL (either in addition to or in contradiction to the official ISO SQL standards).<br />
Fortunately, you can customize your application based on which DB it ends up using, which will be demonstrated by getting the standard deviation of the employees' salaries - built into e.g. PostgreSQL SQL but not available by default in e.g. Firebird.<br />
<br />
In our LoadSalaryGrid procedure, we'll use the SQL for PostgreSQL and build a code solution for all other databases. First detect which database is loaded, below the other lines add:<br />
<syntaxhighlight lang=pascal><br />
...<br />
SalaryGrid.Cells[3,2]:=FQuery.Fields[2].AsString;<br />
FQuery.Close;<br />
// Always commit(retain) an opened transaction, even if only reading<br />
FTran.Commit;<br />
//end of existing code<br />
<br />
if FConn.ConnectorType = 'PostGreSQL' then<br />
begin<br />
// For PostgreSQL, use a native SQL solution:<br />
FQuery.SQL.Text:='select stddev_pop(salary) from employee ';<br />
FTran.StartTransaction;<br />
FQuery.Open;<br />
if not FQuery.EOF then<br />
SalaryGrid.Cells[3,3]:=FQuery.Fields[0].AsString;<br />
FQuery.Close;<br />
// Always commit(retain) an opened transaction, even if only reading<br />
FTran.Commit;<br />
end<br />
else<br />
begin<br />
// For other database, use the code approach:<br />
....see below...<br />
end;<br />
</syntaxhighlight><br />
<br />
Notice the use of ''ConnectorType''; the string used must match exactly. We also properly check for empty results from the query (which might happen if the employee table is empty).<br />
<br />
... now let's implement a code-based solution for other databases that do not support standard deviation:<br />
<syntaxhighlight lang=pascal><br />
// For other databases, use the code approach:<br />
// 1. Get average of values<br />
FQuery.SQL.Text:='select avg(salary) from employee ';<br />
FQuery.Open;<br />
if FQuery.EOF then<br />
SalaryGrid.Cells[3,3]:='No data'<br />
else<br />
begin<br />
Average:=FQuery.Fields[0].AsFloat;<br />
FQuery.Close;<br />
// 2. For each value, calculate the square of (value-average), and add it up<br />
FQuery.SQL.Text:='select salary from employee where salary is not null ';<br />
FQuery.Open;<br />
while not FQuery.EOF do<br />
begin<br />
DifferencesSquared:=DifferencesSquared+Sqr(FQuery.Fields[0].AsFloat-Average);<br />
Count:=Count+1;<br />
FQuery.Next;<br />
end;<br />
// 3. Now calculate the average "squared difference" and take the square root<br />
if Count>0 then //avoid division by 0<br />
SalaryGrid.Cells[3,3]:=FloatToStr(Sqrt(DifferencesSquared/Count))<br />
else<br />
SalaryGrid.Cells[3,3]:='No data'; <br />
end;<br />
FQuery.Close;<br />
</syntaxhighlight><br />
Note that we use ''FQuery.EOF'' to check for empty data (and avoid division by zero errors etc). The loop shows how to:<br />
* retrieve a database value into a variable<br />
* use ''FQuery.Next'' to move to the next record <br />
* properly check if the query dataset has hit the last record, then stop retrieving data.<br />
<br />
The resulting screen should show something like this - note the use of a decimal comma - while your computer may show a decimal point depending on your locale:<br />
<br />
[[File:sqldbtutorial3mainform.png]]<br />
<br />
=== Revisiting our lowest/highest salary ===<br />
<br />
''This section gives some more useful details on SQL but is not required to work through for the rest of the tutorial''<br />
<br />
Now we know how to deal with detecting various database connections, we can adjust the SQL that gets the lowest and highest salary as well to make use of db specific functionality.<br />
<br />
An example: this would work for MS SQL Server by limiting the number of returned rows to just the first:<br />
<syntaxhighlight lang="SQL"><br />
select top 1 <br />
e.first_name, e.last_name, e.salary <br />
from employee e<br />
order by e.salary asc <br />
</syntaxhighlight><br />
to get the lowest salary.<br />
<br />
This efficiently returns one record. Other databases use other syntax, such as the ISO ROWS 1. The diligent SQL student will soon learn not to miss out that important part and request entire large recordsets just for one required record! <br />
<br />
Let's briefly examine other ways to achieve the same thing, that are worth knowing.<br />
<br />
Another way to retrieve the record(s) with the minimum salary would be :''<br />
<syntaxhighlight lang="SQL">SELECT e.first_name, e.last_name, e.salary FROM employee e WHERE e.salary=(SELECT min(salary) FROM employee)</syntaxhighlight><br />
<br />
SQL students would greatly benefit from researching Common Table Expressions. <br />
<br />
A CTE allows a virtual temporary table to be used in a following expression, allowing you to clearly code some very complex queries that otherwise may not be possible. Knowing about CTEs will catapult you ahead of colleagues who have never heard of them! For example the above may be rewritten (example in Microsoft SQL Server syntax) as : ''<br />
<syntaxhighlight lang="SQL">WITH TheMinimum as<br />
(<br />
SELECT min(salary) as MinimumPay FROM Employee<br />
)<br />
SELECT e.first_name, e.last_name, e.salary FROM Employee e WHERE e.salary=(SELECT MinimumPay FROM TheMinimum)</syntaxhighlight><br />
<br />
Several such temporary tables may be chained together, each using the results from the previous tables. You can treat these virtual tables as though they were real tables in the database, using JOINs to link recordsets together. And it can be very useful for quick tests using hardcoded data - this can be run without any database connection :<br />
<syntaxhighlight lang="SQL">WITH TestEmployee as<br />
(<br />
SELECT 'Fred' as first_name, 'Bloggs' as last_name, 10500 as salary<br />
UNION <br />
SELECT 'Joe' as first_name, 'Public' as last_name, 10000 as salary<br />
UNION <br />
SELECT 'Mike' as first_name, 'Mouse' as last_name, 11000 as salary<br />
),<br />
TheMinimum as<br />
(<br />
SELECT min(salary) as MinimumPay FROM TestEmployee<br />
)<br />
SELECT e.first_name, e.last_name, e.salary FROM TestEmployee e WHERE e.salary=(SELECT MinimumPay FROM TheMinimum)</syntaxhighlight><br />
<br />
You can end up with quite long strings for the code of such SQL queries, but it is only ''one'' query and may be called from anywhere where you are limited to a simple single expression - it can be useful to answer complex queries without resorting to functions or stored procedures.<br />
<br />
== Getting data out of normal controls into the database ==<br />
Previously, we have seen:<br />
* how to let SQLDB update the database with data-bound controls (earlier tutorials)<br />
* how to get data out of the database using queries (the section above)<br />
<br />
You can also execute SQL to get arbitrary data back into the database via code. This allows you to use variables or controls that have no db aware equivalent such as sliders or custom controls to enter data into the database, at the expense of a bit more coding.<br />
<br />
As an example, we are going to allow the user to change the lowest and highest salary in the stringgrid.<br />
<br />
For ease of editing, set the grid's ''Options''/''goEditing'' to true; then assign the procedure below to the OnValidate event for the grid, which will be called every time a user has finished updating the grid. <br />
<br />
=== Parameterized queries ===<br />
The following code also demonstrates how to use parameterized queries to avoid SQL injection, fiddling with quoting for string values, date formatting, etc.<br />
<br />
As you can see in the code, you can name your parameters whatever you wish and prefix them with : in the SQL. In code, you can set/get their values by ''<somequery>.Params.ParamByName('<thename>').As'<variabletype>'; the code demonstrates ''.AsFloat'' and ''.AsString''.<br />
<br />
Parameterized queries are especially useful (and can be much faster) if you run the same query, only with different parameters, in a loop (think e.g. bulk loading of data).<br />
<br />
Continuing with our example: after having set up the query SQL and parameters, the transaction is started (and later on committed) as usual, then the query is run by calling ''ExecSQL'' (which does not return a result set; if the SQL statement were e.g. a SELECT or INSERT...RETURNING that does return data, you would use ''Open'' as in the examples above):<br />
<br />
<syntaxhighlight lang=pascal><br />
procedure TForm1.SalaryGridValidateEntry(sender: TObject; aCol, aRow: Integer;<br />
const OldValue: string; var NewValue: String);<br />
begin<br />
// Only these cells have min and max salary:<br />
if (aCol=3) and ((aRow=1) or (aRow=2)) then<br />
begin<br />
// Allow updates to min and max salary if positive numerical data is entered<br />
if StrToFloatDef(NewValue,-1)>0 then<br />
begin<br />
// Storing the primary key in e.g. a hidden cell in the grid and using that in our<br />
// update query would be cleaner, but we can do it the hard way as well:<br />
FQuery.SQL.Text:='update employee set salary=:newsalary '+<br />
' where first_name=:firstname and last_name=:lastname and salary=:salary ';<br />
FQuery.Params.ParamByName('newsalary').AsFloat:=StrToFloatDef(NewValue,0);<br />
FQuery.Params.ParamByName('firstname').AsString:=SalaryGrid.Cells[1,aRow];<br />
FQuery.Params.ParamByName('lastname').AsString:=SalaryGrid.Cells[2,aRow];<br />
FQuery.Params.ParamByName('salary').AsFloat:=StrToFloatDef(OldValue,0);<br />
FTran.StartTransaction;<br />
FQuery.ExecSQL;<br />
FTran.Commit;<br />
LoadSalaryGrid; //reload standard deviation<br />
end<br />
else<br />
begin<br />
// Notify user that his input was wrong... he'll be wondering otherwise:<br />
Showmessage('Invalid salary entered.');<br />
NewValue:=OldValue;<br />
end;<br />
end<br />
else<br />
begin<br />
// Silently discard edits to any other cells<br />
NewValue:=OldValue;<br />
end;<br />
end;<br />
</syntaxhighlight><br />
<br />
Note how we forgot to add a try..except block to this code to nicely catch database errors and display a sensible error message. If you are running the Firebird sample EMPLOYEE database for this tutorial, try to change the salary to a very low value (say 1) and see what happens.<br />
<br />
Finally, while this example showed an UPDATE SQL query, you could just as well run INSERT queries to insert new data programmatically. Also, you can use parameters in any kind of SQL query (SELECT, UPDATE, etc) as long as you use them for fields, not for table/view/procedure names.<br />
<br />
== Summary ==<br />
This tutorial explained:<br />
* how to code for multiple database types<br />
* how to use a login form to decouple db access configuration from your program<br />
* how to retrieve and update data programmatically<br />
<br />
== Code ==<br />
Since November 2012, the code can be found in $(lazarusdir)examples/database/sqldbtutorial3<br />
<br />
If you have an older version (e.g. Lazarus 1.0.2), you can also download the code via <br />
[http://svn.freepascal.org/svn/lazarus/trunk/examples/database/sqldbtutorial3/ the Lazarus SVN website]<br />
<br />
== See also ==<br />
* [[SQLdb Tutorial0/ja]]: Instructions for setting up sample tables/sample data for the tutorial series.<br />
* [[SQLdb Tutorial1/ja]]: First part of the DB tutorial series, showing how to set up a grid that shows database data <br />
* [[SQLdb Tutorial2/ja]]: Second part of the DB tutorial series, showing editing, inserting etc.<br />
* [[SQLdb Tutorial4]]: Fourth part of the DB tutorial series, showing how to use data modules<br />
* [[Lazarus Database Overview/ja]]: Information about the databases that Lazarus supports. Links to database-specific notes.<br />
* [[SQLdb Package]]: information about the SQLdb package<br />
* [[SQLdb Programming Reference]]: an overview of the interaction of the SQLdb database components<br />
* [http://www.freepascal.org/docs-html/fcl/sqldb/usingparams.html using parameters]<br />
* [[SqlDBHowto/ja]]: information about using the SQLdb package<br />
* [[Working With TSQLQuery/ja]]: information about TSQLQuery</div>Aribenhttps://wiki.freepascal.org/SQLdb_Tutorial2/jaSQLdb Tutorial2/ja2024-03-27T15:28:12Z<p>Ariben: /* コードの変更のない組み込みデータベース */</p>
<hr />
<div>{{SQLdb Tutorial2}}<br />
<br />
{{Infobox databases/ja}}<br />
<br />
== 概要 ==<br />
<br />
[[SQLdb Tutorial1/ja]]が済んでいるなら、データベースを表示する基本的なグリッドがあるはずだ<br />
このアプリケーションが機能するためには若干の改良を加えることができる。<br />
=== 動的データベース接続 ===<br />
<br />
これまでは、わかりやすくするために、固定のデータベース サーバー名、データベースの場所、ユーザー名、パスワードを使用してきた。<br />
前述したように、「実際の」アプリケーションでは通常、ユーザーが独自のユーザー名とパスワードを指定できる。<br />
<br />
それらを指定できるようにフォームを変更しよう。標準メニューから 2 つの [[TEdit]] を追加する。 名前のプロパティを「ユーザー名」と「パスワード」に設定する。<br />
肩越しに覗き見されることに対するセキュリティを確保するには、パスワードの PasswordChar プロパティを * (アスタリスク) に設定する。<br />
<br />
接続を簡単にしたい場合 (もちろん安全性は低くなるが)、UserName Text プロパティを SYSDBA などの有効なデータベース ユーザーに設定できる。 パスワード テキスト プロパティをマスターキーのようなデフォルト値に設定することもでき、セキュリティが重要でない場合は開発者のマシンで簡単にテストできるが...<br />
<br />
見た目上、ラベルを追加して何を入力すればよいのかわかるようにすると便利だ。<br />
<br />
また、Firebird/Interbase サーバー上の従業員サンプル データベースに簡単に接続できるように、サーバー名とデータベース パス用の 2 つのテキスト ボックスを追加する。 さらに 2 つの TEdit を追加し、ServerName と DatabaseName という名前を付ける。<br />
<br />
必要に応じて、「Text」プロパティを状況に応じたデフォルトの適切な値に設定できる。 localhost と <code>C:\Program Files\Firebird\Firebird_2_5\examples\empbuild\EMPLOYEE.FDB</code><br />
<br />
ユーザーが入力する必要がある内容を説明するラベルもここで役に立つ。<br />
<br />
明確にするために、設計時コンポーネントから接続情報を削除する。[[TSQLConnector]] コンポーネントで、UserName、Password、DatabaseName、および HostName プロパティからすべてのテキストを削除する。<br />
<br />
さて、最後に、データベース接続コンポーネントに接続方法を指示する必要がある。 これは通常、アプリケーションの実行の開始時にのみ必要になる。 この例では、既存の「Button1」コードが接続をセットアップする良い方法である。<br />
<br />
以下が得られるまでコードを追加。<br />
<br />
<syntaxhighlight lang=pascal><br />
procedure TForm1.Button1Click(Sender: TObject);<br />
begin<br />
SQLQuery1.Close;<br />
//Firebird/Interbaseデータベースの接続設定<br />
// まだ接続していない場合にのみ必要:<br />
if not DBConnection.Connected then<br />
begin<br />
DBConnection.HostName := ServerName.Text;<br />
DBConnection.データベース名 := データベース名.テキスト;<br />
DBConnection.DatabaseName := DatabaseName.Text;<br />
DBConnection.Password := Password.Text;<br />
// これで接続が設定された。それを視覚的に示す。<br />
// 変更はもう行われない可能性がある<br />
ServerName.ReadOnly:=true;<br />
DatabaseName.ReadOnly:=true;<br />
UserName.ReadOnly:=true;<br />
Password.ReadOnly:=true;<br />
end;<br />
SQLQuery1.SQL.Text:= 'select * from CUSTOMER';<br />
DBConnection.Connected:= True;<br />
SQLTransaction1.Active:= True;<br />
SQLQuery1.Open;<br />
end;<br />
</syntaxhighlight><br />
次に、実行して接続できるかどうかをテストする。<br />
<br />
==== SQLite、その他のデータベース ====<br />
<br />
必要に応じて、例えば SQLite の <code>employee.sqlite</code>、DatabaseName TEdit の Text、 プロパティを調整する。 。<br />
<br />
sqlite の場合、HostName、Username、および Password の指定は意味がないため、これらの TEdit を省略できる。 明らかに、上記のコードでは、対応する値を DBConnection に割り当てるのを省略またはコメントアウトする。<br />
Firebird が埋め込まれている場合は、ユーザー名を SYSDBA にハードコーディングする。 sqlite を使用するときにはこれを指定しても問題ない。<br />
<br />
コードは次のようになる:<br />
<br />
<syntaxhighlight lang=pascal><br />
procedure TForm1.Button1Click(Sender: TObject);<br />
begin<br />
SQLQuery1.Close;<br />
//組み込みデータベースの接続設定<br />
// まだ接続していない場合にのみ必要:<br />
if not DBConnection.Connected then<br />
begin<br />
DBConnection.DatabaseName := DatabaseName.Text;<br />
DBConnection.UserName := 'SYSDBA'; //Firebird 埋め込みにはこれが必要。 SQLiteを使用する場合は問題ない<br />
// これで接続が設定された。それを視覚的に示す。<br />
// 変更はもう行われない可能性がある<br />
DatabaseName.ReadOnly:=true;<br />
end;<br />
SQLQuery1.SQL.Text:= 'select * from CUSTOMER';<br />
DBConnection.Connected:= True;<br />
SQLTransaction1.Active:= True;<br />
SQLQuery1.Open;<br />
end;<br />
</syntaxhighlight><br />
<br />
=== データのフィルタリング ===<br />
<br />
多くの場合、テーブルにはユーザーが見たくない大量のデータが含まれている (データベースからクエリを実行し、ネットワーク上を移動するには時間がかかる可能性がある)。米国からの顧客のみを表示する必要があると仮定する。 したがって、「SQLQuery1」の SQL 命令は次のようになる。<br />
<br />
<syntaxhighlight lang="SQL"><br />
select * from CUSTOMER where COUNTRY = 'USA'<br />
</syntaxhighlight><br />
<br />
...これは、コードでは次のように変換される。<br />
<br />
<syntaxhighlight lang=pascal><br />
SQLQuery1.SQL.Text := 'select * from CUSTOMER where COUNTRY = 'USA'';<br />
</syntaxhighlight><br />
<br />
このサンプル アプリケーションでこの命令を使用しない理由は 2 つある。<br />
<br />
まず、単一引用符の使用法に問題がある。 コンパイラーは USA の前の引用符を終了引用符 (最初の引用符は select from... の前にある) として解釈するため、SQL 命令は無効になる。 解決策: 内側の引用符を 2 倍にする。<br />
<br />
<syntaxhighlight lang=pascal>SQLQuery1.SQL.Text := 'select * from CUSTOMER where COUNTRY = ''USA''';</syntaxhighlight><br />
<br />
2 番目の、より重要な理由は、ユーザーがどのような制約でフィルターをかけたいのかがおそらくわからないという事実だ。 ユーザーの柔軟性を制限したくはない。<br />
<br />
この柔軟性を実現するには、まず SQL クエリ ステートメントを変更し、「USA」をプレースホルダー (SQL のパラメータ) に置き換える。Button1click プロシージャを変更して次のように置き換える。<br />
<br />
<syntaxhighlight lang=pascal><br />
SQLQuery1.SQL.Text := 'select * from CUSTOMER';<br />
</syntaxhighlight><br />
<br />
と:<br />
<br />
<syntaxhighlight lang=pascal><br />
SQLQuery1.SQL.Text:= 'select * from CUSTOMER where COUNTRY = :COUNTRY';<br />
</syntaxhighlight><br />
<br />
FPC SQLDB では、SQL パラメーターは先頭のコロンでマークされる (他の言語/環境では ? などの他の規則が使用されます)。 ユーザーがフィルターの値を入力できるようにするために、フォームに ''TEdit'' コンポーネントを配置する。 「Text」プロパティの値を削除する。<br />
<br />
これで、TEdit に入力されたテキストを取得し、TSQLQuery の 'Params' プロパティを使用して SQL COUNTRY パラメータを入力できるようになった。 これを前のステートメントの下に追加する。<br />
<br />
<syntaxhighlight lang=pascal><br />
SQLQuery1.Params.ParamByName('COUNTRY').AsString := Edit1.Text;<br />
</syntaxhighlight><br />
<br />
パラメータは位置または名前で指定できます。 名前を使用すると、ソース コードの読みやすさが向上し、既存のパラメーターの途中にさらにパラメーターを挿入する場合に明らかに役立つ。<br />
<br />
.AsString を使用して文字列値をパラメータに割り当てる。 整数パラメータ、ブール値パラメータなどに対して同等のプロパティ割り当てがある。<br />
<br />
これまでのコードでは、フィルターの使用を強制されている。 ユーザーが編集ボックスに空の値を指定した場合、レコードは表示されない。 おそらくこれは私たちが望んでいることではない。 空の値をテストし、それに応じてクエリを作成しよう。 最終的には次のような手順になるはずだ。<br />
<br />
<syntaxhighlight lang=pascal><br />
procedure TForm1.Button1Click(Sender: TObject);<br />
begin<br />
SQLQuery1.Close;<br />
// Firebird/Interbaseデータベースの接続設定<br />
// まだ接続していない場合にのみ必要:<br />
if not DBConnection.Connected then<br />
begin<br />
DBConnection.HostName := ServerName.Text;<br />
DBConnection.DatabaseName := DatabaseName.Text;<br />
DBConnection.Username := UserName.Text;<br />
DBConnection.Password := Password.Text;<br />
// これで接続が設定された。それを視覚的に示す。<br />
// 変更はもう行われない可能性がある<br />
ServerName.ReadOnly:=true;<br />
DatabaseName.ReadOnly:=true;<br />
UserName.ReadOnly:=true;<br />
Password.ReadOnly:=true;<br />
end;<br />
// すべてのレコードを表示するか、ユーザーがフィルター基準を指定した場合はフィルターする<br />
if Edit1.Text='' then<br />
SQLQuery1.SQL.Text := 'select * from CUSTOMER where COUNTRY = :COUNTRY';<br />
else<br />
begin<br />
SQLQuery1.SQL.Text := 'select * from CUSTOMER where COUNTRY = :COUNTRY';<br />
SQLQuery1.Params.ParamByName('COUNTRY').AsString := Edit1.Text;<br />
end;<br />
DBConnection.Connected:= True;<br />
SQLTransaction1.Active:= True;<br />
SQLQuery1.Open;<br />
end;<br />
</syntaxhighlight><br />
<br />
ここで、Edit1 を使用してフィルタリングを少し試す。 データベースに存在しない国を入力すると、空のグリッドが表示される。<br />
<br />
=== エラー処理 ===<br />
<br />
アプリケーションは実行されるはずだが、場合によっては問題が発生する可能性がある。<br />
データベース、さらには組み込みデータベースもクラッシュする可能性があり (データベース サーバーがクラッシュした場合、ディスクがいっぱいになった場合、または単にバグが原因である場合など)、アプリケーションがハングしたままになる。<br />
<br />
したがって、データベース (実際には任意の外部プロセス) へのアクセスは、「常に」、try ... 例外および/または try ...finally 構造に統合される必要がある。 これにより、データベース エラーが確実に処理され、ユーザーが孤立することがなくなる。 このサンプル アプリケーションの基本的なルーチンは次のようになる。<br />
<br />
<syntaxhighlight lang=pascal><br />
begin<br />
try<br />
SQLQuery1.Close;<br />
...<br />
SQLQuery1.Open;<br />
except<br />
//一般的なデータベース エラーである EDatabaseErrorが必要だが、ここでは Firebird/Interbase を扱っているため、次のようになる:<br />
on E: EDatabaseError do<br />
begin<br />
MessageDlg('Error','A database error has occurred. Technical error message: ' + E.Message,mtError,[mbOK],0);<br />
Edit1.Text:='';<br />
end;<br />
end;<br />
end;<br />
</syntaxhighlight><br />
<br />
==== SQLite、PostgreSQL、その他のデータベース ====<br />
<br />
さらに詳細が必要な場合は、より汎用的な EDatabaseError を使用するか、使用可能な場合は独自の特殊な DatabaseError を使用できる。<br />
例えば。 SQLite と FPC 2.6.1 以前の PostgreSQL ドライバーには特殊な E*DatabaseError がなく、EDatabaseError を使用する必要がある。 FPC (開発版)の PostgreSQL に EPQDatabaseError がある。<br />
<br />
== Editing data using the grid ==<br />
<br />
== グリッドを使用したデータの編集 ==<br />
<br />
=== 編集 ===<br />
<br />
これまで、グリッド内のデータを編集しようとしても、変更は保存されなかった。 これは、「SQLQuery1」が適切なタイミングでデータベース トランザクションに変更を送信するように指示されていないためだ。<br />
これを修正し、データベースにトランザクションをコミットして、すべての変更が書き込まれるようにする必要がある。 このためには、次のようなコードを使用する。<br />
<br />
<syntaxhighlight lang=pascal><br />
SQLQuery1.ApplyUpdates; // ユーザーが生成した変更をデータベースに渡す...<br />
SQLTransaction1.cmmit; //...そしてトランザクションを使用してコミットする。<br />
//SQLTransaction1.Active は false <br />
</syntaxhighlight><br />
<br />
編集 (挿入、更新、削除) がデータベースに書き込まれることを確認したいとする。<br />
<br />
* ユーザーがフィルタリング基準を変更し、ボタンを押してデータベースにクエリを実行したとき<br />
* フォームを閉じたとき<br />
<br />
これら 2 つのインスタンスで呼び出される、このために別のプロシージャを作成することは理にかなっている<br />
コードに移動し、ここに空の行を追加する。<br />
<br />
<syntaxhighlight lang=pascal><br />
TForm1 = class(TForm)<br />
Button1: TButton;<br />
Datasource1: TDatasource;<br />
DBGrid1: TDBGrid;<br />
Edit1: TEdit;<br />
DBConnection: TIBConnection;<br />
SQLQuery1: TSQLQuery;<br />
SQLTransaction1: TSQLTransaction;<br />
*****ここに空行を挿入****<br />
procedure Button1click(Sender: TObject);<br />
procedure Formclose(Sender: TObject; var Closeaction: Tcloseaction);<br />
private<br />
</syntaxhighlight><br />
<br />
次に、次のように入力す。る<br />
<br />
<syntaxhighlight lang=パスカル><br />
procedure SaveChanges;<br />
</syntaxhighlight><br />
<br />
shift-ctrl-c (デフォルトの組み合わせ) を押すと、コード補完によって対応するプロシージャ本体が自動的に作成される。<br />
<br />
エラー処理を追加して、トランザクションがアクティブであることを確認する必要がある。このコードは、トランザクションがまだアクティブではないときに初めてボタンを押したときにも呼び出されることを覚えておくこと。ここで:<br />
<br />
<syntaxhighlight lang=pascal><br />
procedure Tform1.SaveChanges;<br />
// Saves edits done by user, if any.<br />
begin<br />
try<br />
if SQLTransaction1.Active then<br />
// 開始されたトランザクション内にいる場合のみ。;<br />
// それ以外の場合は、「非アクティブなデータセットでは操作を実行できません」というメッセージが表示される。<br />
begin<br />
SQLQuery1.ApplyUpdates; // ユーザーが生成した変更をデータベースに渡します...<br />
SQLTransaction1.Commit; //...そしてトランザクションを使用してコミットする。<br />
//SQLTransaction1.Active は false<br />
end;<br />
except<br />
on E: EDatabaseError do<br />
begin<br />
SQLTransaction1.Rollback;<br />
MessageDlg('Error', 'A database error has occurred. Technical error message: ' +<br />
E.Message, mtError, [mbOK], 0);<br />
Edit1.Text := '';<br />
end;<br />
end;<br />
end;<br />
</syntaxhighlight><br />
<br />
次に、適切な時点でこのプロシージャを呼び出す必要がある。<br />
<br />
<syntaxhighlight lang=pascal><br />
procedure Tform1.Button1click(Sender: TObject);<br />
begin<br />
SaveChanges; //変更を保存しトランザクションをコミット<br />
try<br />
SQLQuery1.Close;<br />
....<br />
</syntaxhighlight><br />
<br />
そして:<br />
<br />
<syntaxhighlight lang=pascal><br />
procedure Tform1.Formclose(Sender: TObject; var Closeaction: Tcloseaction);<br />
begin<br />
SaveChanges; //変更を保存しトランザクションをコミット<br />
SQLQuery1.Close;<br />
....<br />
</syntaxhighlight><br />
<br />
次に、dbgrid で行われた編集がデータベースに保存されるかどうかをテストして確認する。<br />
<br />
=== 主キー列の非表示 ===<br />
<br />
多くの場合、自動採番/生成された主キーは参照整合性を維持することのみを目的としているため、ユーザーに表示されたくないことがある。 ユーザーがそれらを見た場合、数値を編集しようとしたり、数値が変わったり、数値にギャップがあるなどのことに腹を立てたりする可能性がある。<br />
<br />
この例では、CUST_NO が主キーで、コンテンツはトリガーとシーケンス/ジェネレーターを使用して Firebird によって自動生成される。 これは、CUST_NO を指定せずに新しいレコードを挿入できることを意味する。Firebird が自動的に作成する。<br />
<br />
CUST_NO を含めないように SQLQuery1.SQL.Text プロパティを変更することもできますが、これによりデータ編集時に問題が発生する。このような状況では、問題の行/レコードを一意に識別するために主キーが必要になる。<br />
<br />
したがって、テーブル内のすべての列/フィールドをクエリするトリックを使用するが、Button1Click プロシージャの最初のフィールド CUST_NO: がグリッドに表示されないようにして、次のようにコードを追加する:<br />
<br />
<syntaxhighlight lang=pascal><br />
procedure Tform1.Button1click(Sender: TObject);<br />
begin<br />
...<br />
SQLQuery1.Open;<br />
// クエリの最初の列である主キー列を非表示にする<br />
// DBGrid が列を作成した後でのみこれを行うことができます<br />
DBGrid1.Columns[0].Visible:=false;<br />
</syntaxhighlight><br />
<br />
<br />
再コンパイルし、主キー列が本当に非表示になっているかどうかを確認します。<br />
<br />
==== SQLite、その他のデータベース ====<br />
<br />
* その他のデータベース: 他の多くのデータベースは、自動生成されたフィールド コンテンツを提供するために「autonumber」または「autoinc」タイプのフィールドを使用します。 テーブル定義を変更して、それが機能するかどうかを確認してください。<br />
* Sqlite: 整数の主キーを使用しているため、上記の例は SQLite でそのまま機能します。 詳細については、[http://www.sqlite.org/autoinc.html ドキュメント] を参照してください。<br />
<br />
=== 新しいデータの挿入 ===<br />
<br />
CUST_NO 情報なしで新しい行/レコードを挿入すると、次のエラー メッセージが表示されることに気づいたかもしれない: <tt>Field CUST_NO is required, but not supplied</tt>。 これは、前のセクションのように CUST_NO 列を非表示にした場合にも発生する。<br />
<br />
理由: Lazarus は CUST_NO が必要であると考えている。 これはそれほど奇妙ではない。これは主キーであり、データベース内の基になるテーブル定義で必須であると示されているからである。<br />
<br />
このフィールドが実際には必要ないことを Lazarus に指示できれば、空の値 (=NULL 値) をデータベースに渡すことができる。<br />
幸いなことに、クエリのフィールド オブジェクトには、まさにそれを行う ''Required'' プロパティがある。<br />
<br />
コードを次のように変更する。<br />
<br />
<syntaxhighlight lang=pascal><br />
SQLQuery1.Open;<br />
{<br />
空白 (=NULL) CUST_NO 値を挿入しても問題が発生しないことを確認のこと。例:<br />
フィールド CUST_NO は必須だが、指定されていない<br />
Lazarus に、CUST_NO は主キーではあるが、新しいレコードを挿入するとき<br />
必須ではないことを伝える必要がある。<br />
}<br />
SQLQuery1.FieldByName('CUST_NO').Required:=false;<br />
// クエリの最初の列である主キー列を非表示にする。<br />
// DBGrid が列を作成した後でのみこれを行うことができる<br />
DBGrid1.Columns[0].Visible:=false;<br />
</syntaxhighlight><br />
<br />
=== データを削除する ===<br />
<br />
ユーザーにマウスを使用してこれを実行させることができる。 この機能については 1 行もコーディングする必要はない。<br />
<br />
「データ コントロール」タブで、「TDBNavigator」コンポーネントを選択し、フォームのグリッドの上にドロップする。<br />
<br />
ナビゲーターのリンク先を指定するには、オブジェクトインスペクタを使用して、ナビゲーターの ''DataSource'' プロパティを既存のデータソース ('DataSource1') に設定する。<br />
これで、「DBNavigator」のボタンを使用してレコードを削除できるだけでなく、レコードを挿入したり、レコード内を移動したりすることもできる。 また、セル/フィールドを編集する場合、「キャンセル」ボタンを使用して編集をキャンセルすることができる。<br />
<br />
ユーザーが {{keypress|Delete}} キーを使用してグリッド上の行を削除できるようにするには、uses 句に ''LCLType'' (これにはキー コードの定義が含まれる) を追加する。<br />
<br />
<syntaxhighlight lang=pascal><br />
uses<br />
Classes, SysUtils, sqldb, pqconnection, DB, FileUtil, Forms,<br />
Controls, Graphics, Dialogs, DBGrids, StdCtrls, DbCtrls, LCLType;<br />
</syntaxhighlight><br />
<br />
... 次に、グリッドの KeyUp イベントを処理する。このイベントは、グリッド内にある場合にキーが放されたときに発生する。 ただし、ユーザーがフィールドを編集していないことを確認する必要がある。ユーザーは、作業中のレコードではなく文字を削除するために {{keypress|Delete}} キーを使用する可能性が高いためである。<br />
<br />
グリッドを選択し、イベントに移動して次のように OnKeyUp イベントを作成する。<br />
<br />
<syntaxhighlight lang=pascal><br />
procedure TForm1.DBGrid1KeyUp(Sender: TObject; var Key: Word; Shift: TShiftState<br />
);<br />
begin<br />
// del キーが押されたことを確認し、データを編集していない限り<br />
// それに応じて現在のレコードを削除する<br />
if (key=VK_DELETE) and (not(DBGrid1.EditorMode)) then<br />
begin<br />
//... 現在のレコードを削除し、データベースに更新を適用する:<br />
SQLQuery1.Delete;<br />
SQLQuery1.ApplyUpdates;<br />
end;<br />
end; <br />
</syntaxhighlight><br />
<br />
{{Note| デフォルトでは、TDBGrid プロパティ Options / dgDisableDelete は false に設定されている。これは、ユーザーが {{keypress|ctrl}}-{{keypress|delete}} キーの組み合わせを使用して任意のレコードを削除できることを意味する。 この動作は望ましくないかもしれない。}}<br />
<br />
== 要約 ==<br />
<br />
ここまで手順を進めてきたら、データベースからデータを取得し、フィルタリングし、グリッド内のデータを編集および削除できる。 コードは次のようになる:<br />
<br />
<syntaxhighlight lang=pascal><br />
unit sqldbtutorial1unit;<br />
<br />
{$mode objfpc}{$H+}<br />
<br />
interface<br />
<br />
uses<br />
Classes, SysUtils, sqldb, pqconnection, DB, FileUtil, Forms,<br />
Controls, Graphics, Dialogs, DBGrids, StdCtrls, DbCtrls, LCLType;<br />
type<br />
<br />
{ TForm1 }<br />
<br />
TForm1 = class(TForm)<br />
Button1: TButton;<br />
DatabaseName: TEdit;<br />
Datasource1: TDatasource;<br />
DBGrid1: TDBGrid;<br />
Dbnavigator1: Tdbnavigator;<br />
Edit1: TEdit;<br />
Label2: Tlabel;<br />
Label3: Tlabel;<br />
Label4: Tlabel;<br />
Label5: Tlabel;<br />
Password: TEdit;<br />
UserName: TEdit;<br />
ServerName: TEdit;<br />
DBConnection: TIBConnection;<br />
Label1: TLabel;<br />
SQLQuery1: TSQLQuery;<br />
SQLTransaction1: TSQLTransaction;<br />
procedure SaveChanges;<br />
procedure Button1click(Sender: TObject);<br />
procedure Formclose(Sender: TObject; var Closeaction: Tcloseaction);<br />
private<br />
{ private declarations }<br />
public<br />
{ public declarations }<br />
end;<br />
<br />
var<br />
Form1: TForm1;<br />
<br />
implementation<br />
<br />
{$R *.lfm}<br />
<br />
{ TForm1 }<br />
<br />
procedure Tform1.Savechanges;<br />
// もしあれば、ユーザーによる編集を保存する。Saves edits done by user, if any.<br />
begin<br />
try<br />
if SQLTransaction1.Active then<br />
// トランザクションを開始したときのみ<br />
// さもないと"Operation cannot be performed on an inactive dataset"にであることになる。<br />
begin<br />
SQLQuery1.ApplyUpdates; //ユーザーによる変更をデータベースに戻すPass user-generated changes back to database...<br />
SQLTransaction1.Commit; //... トランザクションを用いてコミット<br />
//SQLTransaction1.Active now is false<br />
end;<br />
except<br />
on E: EDatabaseError do<br />
begin<br />
SQLTransaction1.Rollback;<br />
MessageDlg('Error', 'A database error has occurred. Technical error message: ' +<br />
E.Message, mtError, [mbOK], 0);<br />
Edit1.Text := '';<br />
end;<br />
end;<br />
end;<br />
<br />
procedure TForm1.DBGrid1KeyUp(Sender: TObject; var Key: Word; Shift: TShiftState<br />
);<br />
begin<br />
// データを編集しているとき以外に<br />
// Delキーが押され、それに応じて現在のレコードを消去する。<br />
if (key=VK_DELETE) and (not(DBGrid1.EditorMode)) then<br />
begin<br />
//... delete current record and apply updates to db:<br />
SQLQuery1.Delete;<br />
SQLQuery1.ApplyUpdates;<br />
end;<br />
end; <br />
<br />
procedure Tform1.Button1click(Sender: TObject);<br />
begin<br />
SaveChanges; //変更を保存し、トランザクションをコミット<br />
try<br />
SQLQuery1.Close;<br />
//Firebird/Interbaseデータベースの接続設定<br />
//まだ、接続していないときにのみ必要である:<br />
if not DBConnection.Connected then<br />
begin<br />
DBConnection.HostName := ServerName.Text;<br />
DBConnection.DatabaseName := DatabaseName.Text;<br />
DBConnection.Username := UserName.Text;<br />
DBConnection.Password := Password.Text;<br />
// コネクションを張り、<br />
// 変更はもうないと視覚的に訴える<br />
ServerName.ReadOnly:=true;<br />
DatabaseName.ReadOnly:=true;<br />
UserName.ReadOnly:=true;<br />
Password.ReadOnly:=true;<br />
end;<br />
// すべてのレコードもしくはユーザーによって定義されたフィルタ定義で表示<br />
if Edit1.Text='' then<br />
SQLQuery1.SQL.Text := 'select * from CUSTOMER'<br />
else<br />
begin<br />
SQLQuery1.SQL.Text := 'select * from CUSTOMER where COUNTRY = :COUNTRY';<br />
SQLQuery1.Params.ParamByName('COUNTRY').AsString := Edit1.Text;<br />
end;<br />
DBConnection.Connected := True;<br />
SQLTransaction1.Active := True; //Starts a new transaction<br />
SQLQuery1.Open;<br />
{<br />
空(=NULL)値を挿入しても問題ない、即ち、エラーメッセージ "Field CUST_NO is required, but not supplied"<br />
が現れないようにすること。CUST_NOがプライマリキーであるときLazarusにそれを教える必要がある<br />
新しいレコードが挿入されるときには必要ない<br />
}<br />
SQLQuery1.FieldByName('CUST_NO').Required:=false;<br />
{<br />
クエリの最初のカラムであるプライマリキーを隠す。<br />
これはDBGridがカラムを生成するときに一度だけ行える<br />
}<br />
DBGrid1.Columns[0].Visible:=false;<br />
except<br />
// EDatabaseErrorは一般的なエラーだ; <br />
// 例えば、Firebird/Interbaseにおいては、EIBDatabaseErrorのような<br />
// データベースに特異なものを用いたほうがいいかもしれない<br />
on E: EDatabaseError do<br />
begin<br />
MessageDlg('Error', 'A database error has occurred. Technical error message: ' +<br />
E.Message, mtError, [mbOK], 0);<br />
Edit1.Text := '';<br />
end;<br />
end;<br />
end;<br />
<br />
procedure Tform1.Formclose(Sender: TObject; var Closeaction: Tcloseaction);<br />
begin<br />
SaveChanges; //変更を保存し、トランザクションをコミットする<br />
SQLQuery1.Close;<br />
SQLTransaction1.Active := False;<br />
DBConnection.Connected := False;<br />
end;<br />
<br />
end.<br />
</syntaxhighlight><br />
<br />
== コード変更のない組み込みデータベース ==<br />
===Windows 上のFirebird ===<br />
Windows の Firebird ユーザーへのボーナス: このチュートリアルに従っている場合は (基本的な例しか実行していない場合でも)、埋め込まれた Firebird ライブラリの fbembed.dll の名前が fbclient.dll に変更されている。 これにより、Lazarus は通常の Firebird サーバ (別のマシンまたはローカルマシンのいずれか) に接続できるようになる。 ただし、サーバをセットアップせずに、employee.fdb データベースをアプリケーション ディレクトリにコピーし、アプリケーションを実行し、サーバ名 TEdit をクリアして、埋め込まれた Firebird を使用してデータベース ファイルに直接接続することもできる。<br />
<br />
これは、データベース アプリケーションをエンド ユーザーに展開したいが、サーバのインストールに手間をかけたくない (サーバがすでにインストールされているかどうか、バージョンが正しいかどうかを確認する、ユーザーにファイアウォールを確認させるなど) 場合に最適である。<br />
<br />
詳細については、[[Firebird embedded]] を参照されたい。<br />
<br />
2011 年 9 月: Free Pascal の最近の開発 (SVN) バージョンでは、FPC は最初に fbembed.dll をロードするので、これが機能するために fbclient.dll の名前を変更する必要はなくなった。<br />
<br />
=== Linux/macOS/Unix 上の Firebird ===<br />
これを Linux/macOS で動作させる方法があるはずだ。 ヒントとリンクについては、[[Firebird]]を参照されたい。 Wiki の更新は大歓迎である。<br />
<br />
=== SQLite ===<br />
SQLite は確かに組み込み機能を提供するが、その一方で、クライアント/サーバのセットアップは許可されていない。 上記のチュートリアルに従うと、データベース (SQLite と Firebird など) の切り替えがそれほど難しい作業ではないことがわかる。<br />
<br />
その他のデータベース<br />
データベースでも同様の機能が提供されている場合がある。 他のデータベース システム用のこの Wiki の更新も歓迎である。<br />
<br />
== 以下も参照のこと ==<br />
<br />
* [[SQLdb Tutorial0/ja]]: Instructions for setting up sample tables/sample data for the tutorial series.<br />
* [[SQLdb Tutorial1/ja]]: First part of the DB tutorial series, showing how to set up a grid that shows database data<br />
* [[SQLdb Tutorial3]]: Third part of the DB tutorial series, showing how to program for multiple databases and use a login form<br />
* [[SQLdb Tutorial4]]: Fourth part of the DB tutorial series, showing how to use data modules<br />
* [[Lazarus Database Overview/ja]]: Information about the databases that Lazarus supports. Links to database-specific notes.<br />
* [[SQLdb Package]]: information about the SQLdb package<br />
* [[SQLdb Programming Reference]]: an overview of the interaction of the SQLdb database components<br />
* [[SqlDBHowto]]: information about using the SQLdb package<br />
* [[Working With TSQLQuery]]: information about TSQLQuery</div>Aribenhttps://wiki.freepascal.org/Portal:Windows/jaPortal:Windows/ja2024-03-27T14:46:09Z<p>Ariben: </p>
<hr />
<div>{{Index-Portal}}<br />
<br />
{{Portal_Head2|ee9999|<big>{{PAGENAME}}</big>|ffdddd|000000}}<br />
{| width="100%" class = "wikitable"<br />
| valign="top" |<br />
[[File:Logo Windows 01.png|right]]<br />
This portal provides an overview of development for Windows (and with limitations also for ReactOS) with Lazarus and Free Pascal.<br />
|- <br />
| valign="top" |<br />
<div style="margin-left:1em"><br />
<br />
{{Portal_Head2|87CEFA|'''Related topics'''}}<br />
'''Platform Portals:''' [[Portal:Android|Android]] - [[Portal:Embedded|Embedded]] - [[Portal:FreeBSD|FreeBSD]] - [[Portal:iOS|iOS]] - [[Portal:Linux|Linux]] - [[Portal:Mac|Mac]] - [[Portal:WinCE|WinCE]] - [[Portal:Windows|Windows]]<br />
<br />
'''Topic Portals:''' [[Portal:New Users|<font color=green>'''New Users'''</font>]] - [[Portal:Databases|Database Development]] - [[Portal:Game Development|Game Development]] - [[Portal:Hardware and Robotics|Hardware and Robotics]] - [[Portal:HowTo Demos|HowTo Demos]] - [[Portal:SciTech|Science and Technology]] - [[Portal:Web Development|Web Development]]<br />
<br />
'''Categories:''' '''[[:Category:Windows|Windows]]''' - '''[[:Category:WinCE|WinCE]]''' <br />
</div><br />
|}<br />
<gallery><br />
File:freepascal.png<br />
File:Testdpi125fixedM12P9.png<br />
File:spina thyr 3 3 screenshot winxp.jpg<br />
File:Windows 8.png<br />
File:ReactOS.png<br />
</gallery><br />
<div style="float:left; width:55%;"> <!-- Both "width" values should add up to 100% --><br />
<br />
{{Portal_Head|ee9999|'''ここから始めよう'''|ffdddd|000000||Template:Portal:Windows/Installation/ja}}<br />
<!-- ------------------------ START HERE ---------------------- --><br />
{| width="100%" class = "wikitable"<br />
| valign="top" |<br />
{{Portal:Windows/Installation/ja}}<br />
|}<br />
<br />
{{Portal_Head|ee9999|開発テクニック|ffdddd|000000||Template:Portal:Windows/Development_Techniques/ja}}<br />
<!-- ------------------------ DEVELOPMENT TECHNIQUES ---------------------------- --><br />
{| width="100%" class = "wikitable"<br />
| valign="top" |<br />
{{Portal:Windows/Development_Techniques/ja}}<br />
|}<br />
<br />
{{Portal_Head|ee9999|APIとヘッダ|ffdddd|000000||Template:Portal:Windows/APIs and Headers/ja}}<br />
<!-- ------------------------ APIS AND HEADERS ---------------------------- --><br />
{| width="100%" class = "wikitable"<br />
| valign="top" |<br />
{{Template:Portal:Windows/APIs and Headers}}<br />
|}<br />
</div><br />
<div style="float:right; width:44%"> <!-- Both "width" values should add up to 100% --><br />
<br />
{{Portal_Head|ee9999|特別な話題|ffdddd|000000||Template:Portal:Windows/Special Topics/ja}}<br />
<!-- ------------------------ SPECIAL TOPICS ---------------------------- --><br />
{| width="100%" class = "wikitable"<br />
| valign="top" |<br />
{{Portal:Windows/Special Topics/ja}}<br />
|}<br />
</div><br />
<br />
[[Category:Windows|!Windows Portal/ja]]<br />
[[Category:Portals|Windows Portal/ja]]</div>Aribenhttps://wiki.freepascal.org/Portal:New_Users/jaPortal:New Users/ja2024-03-27T02:50:05Z<p>Ariben: </p>
<hr />
<div>{{Portal_New_Users(pg)}}<br />
{{Index-Portal}}<br />
__NOTOC__<br />
<br />
{{Portal_Head2|00a0cb|<big>{{PAGENAME}}</big>|dfe2eb|000000}}<br />
{| width="100%" class = "wikitable"<br />
| valign="top" |<br />
[[File:NewUserLogo.png|right]]<br />
このポータルは、Free PascalとLazarusの新規ユーザー向けに作成されている。新規ユーザーが最初に出会う場所として、Free PascalとLazarusについて学ぶための場所として意図されている。このページのトピックやチュートリアルは、以前にFree PascalとLazarusを使用したことがない人を対象に、シンプルで要点を押さえたものであるべきである。<br />
|- <br />
| valign="top" |<br />
<div style="margin-left:1em"><br />
<br />
{{Portal_Head2|87CEFA|'''関連する話題'''}}<br />
'''Platform Portals:''' [[Portal:Android|Android]] - [[Portal:Embedded|Embedded]] - [[Portal:FreeBSD|FreeBSD]] - [[Portal:iOS|iOS]] - [[Portal:Linux|Linux]] - [[Portal:Mac|Mac]] - [[Portal:WinCE|WinCE]] - [[Portal:Windows|Windows]]<br />
<br />
'''Topic Portals:''' <font color=green>[[Portal:New Users|'''New Users''']]</font> - [[Portal:Databases/ja|Database 開発]] - [[Portal:Game Development|Game Development]] - [[Portal:Hardware and Robotics|Hardware and Robotics]] - [[Portal:HowTo Demos|HowTo Demos]] - [[Portal:SciTech|Science and Technology]] - [[Portal:Web Development|Web Development]]<br />
<br />
</div><br />
|}<br />
<br />
<div style="float:left; width:49%;”><br />
<br />
{{Portal_Head|00a0cb|'''ここから始めよう'''|dfe2eb|000000||Template:Portal:New Users/Start Here/ja}}<br />
<!-- ------------------------------ START HERE ---------------------------------- --><br />
{| width="100%" class = "wikitable"<br />
| valign="top" |<br />
{{Template:Portal:New Users/Start Here/ja}}<br />
|}<br />
</div><br />
<br />
<div style="float:right; width:49%;”> <!-- Both "width" values should add up to 100% --><br />
<br />
{{Portal_Head|00a0cb|'''リソース'''|dfe2eb|000000||Template:Portal:New Users/Resources/ja}}<br />
<!-- ------------------------------ RESOURCES ------------------------------------ --><br />
{| width="100%" class = "wikitable"<br />
| valign="top" |<br />
{{Template:Portal:New Users/Resources/ja}}<br />
|}<br />
<br/><br />
</div></div>Aribenhttps://wiki.freepascal.org/SQLdb_Programming_Reference/jaSQLdb Programming Reference/ja2024-03-26T22:18:15Z<p>Ariben: Created page with "{{SQLdb Programming Reference}} {{Infobox databases/ja}} == ドキュメンテーション == Please see the official documentation at [http://www.freepascal.org/docs-html/fc..."</p>
<hr />
<div>{{SQLdb Programming Reference}}<br />
<br />
{{Infobox databases/ja}}<br />
== ドキュメンテーション ==<br />
Please see the official documentation at [http://www.freepascal.org/docs-html/fcl/sqldb/index.html SQLDB documentation]. <br />
<br />
This article attempts to give some more detail about SQLDb; however the official documentation is authorative.<br />
<br />
==Class Structure==<br />
The following diagram attempts to show the hierarchy and required links of the MAIN components involved in SQLdb. It is certainly not exhaustive, nor does it use any "proper" diagram structure, so please don't try to read too much into it. I hope it will make it easier to work out which bits of the source code you need to look at to really work out what is happening.<br />
<br />
[[Image:Laz SqlDB components.png]]<br />
<br />
====Notes====<br />
* The link from TDatabase to TTransaction is Transactions, and is a list, implying many transactions are possible for the one database. However, a new link is defined from TSQLConnection to TSQLTransaction which is Transaction - a single transaction per database. This does not actually hide the previous link, but only the new link is published, and it is probably inadvisable to use the ancestor's link.<br />
* Some of the inherited links need to be typecast to the new types to be useful. You can't call SQLQuery.Transaction.Commit, as Commit is only defined in TSQLTransaction. Call SQLTransaction.Commit, or "(SQLQuery.Transaction as TSQLTransaction).Commit"<br />
<br />
==Interaction==<br />
===TConnection===<br />
Documentation: [http://www.freepascal.org/docs-html/fcl/sqldb/tsqlconnection.html TSQLConnection documentation]<br />
<br />
A [[TConnection]] represents a connection to an SQL database. In daily use, you will use the descendent for a specific database (e.g. TIBConnection for Interbase/Firebird), but it is possible to use TConnection if you are trying to write database factory/database independent applications (note: it's probably more advisable to use [http://www.freepascal.org/docs-html/fcl/sqldb/tsqlconnector.html TSQLConnector]).<br />
In this object, you specify connection-related items such as hostname, username and password.<br />
Finally, you can connect or disconnect (using the .Active or .Connected property)<br />
<br />
Most database allow muliple concurrent connections from the same program/user.<br />
<br />
===TSQLTransaction===<br />
Documentation: [http://www.freepascal.org/docs-html/fcl/sqldb/tsqltransaction.html TSQLTransaction]<br />
<br />
This object represents a transaction on the database. In practice, at least one transaction needs to be active for a database, even if you only use it for reading data.<br />
When using a single transaction, set the TConnection.Transaction property to the transaction to set the default transaction for the database; the corresponding TSQLTransaction.Database property should then automatically point to the connection.<br />
<br />
Setting a [[TSQLTransaction]] to .Active/calling .StartTransaction starts a transaction; calling .Commit or .RollBack commits (saves) or rolls back (forgets/aborts) the transaction. You should surround your database transactions with these unless you use .Autocommit or CommitRetaining.<br />
<br />
===TSQLQuery===<br />
Documentation: [http://www.freepascal.org/docs-html/fcl/sqldb/tsqlquery.html TSQLQuery documentation]<br />
<br />
See [[Working With TSQLQuery]] for more details.<br />
<br />
[[TSQLQuery]] is an object that embodies a dataset from a connection/transaction pair using its SQL property to determines what data is retrieved from the database into the dataset.<br />
<br />
When working with it, you therefore need to at least specify the transaction, connection amd SQL properties.<br />
The TSQLQuery is an important part in the chain that links databound controls to the database. As said, the SQL property determines what SELECT query is run against the database to get data.<br />
FPC will try to determine what corresponding SQL INSERT, UPDATE and DELETE statements should be used in order to process user/program generated data changes.<br />
If necessary, the programmer can fine tune this and manually specify the InsertSQL, UpdateSQL and DeleteSQL properties.<br />
<br />
===DataSource===<br />
A [[TDataSource]] object keeps track of where in a dataset (such as TSQLQuery) data bound components are. The programmer should specify the corresponding TSQLQuery object for this to work.<br />
<br />
===Databound controls such as DBGrid===<br />
These controls must be linked to a DataSource. They will often have properties that indicate what fields in the DataSource they show.<br />
<br />
==Data modules==<br />
[[Data module]]s can be used to store non-visual components such as '''T*Connection''', '''TSQLTransaction''', '''TSQLQuery''' etc. Data modules also let you share components between forms.<br />
<br />
See [[SQLdb Tutorial4]].</div>Aribenhttps://wiki.freepascal.org/SqlDBHowto/jpSqlDBHowto/jp2024-03-26T22:15:43Z<p>Ariben: Created page with "{{SqlDBHowto}} {{Infobox databases/ja}} This text is setup as a 'how-to'. I want to answer a number of questions one by one, and explain how you can use the various classes...."</p>
<hr />
<div>{{SqlDBHowto}}<br />
<br />
{{Infobox databases/ja}}<br />
<br />
This text is setup as a 'how-to'. I want to answer a number of questions one by one, and explain how you can use the various classes. All those questions are put one after the other and form a sort of tutorial. <br />
<br />
I will try to word it in such a way that the text can be used for Lazarus as well as Free Pascal. However, the examples are for FreePascal (i.e. they are console applications.)<br />
<br />
== Where can I find official documentation? ==<br />
<br />
Please see the official documentation at [http://www.freepascal.org/docs-html/fcl/sqldb/index.html SQLDB documentation]. <br />
<br />
== How to connect to a database server? ==<br />
<br />
SqlDB doesn't connect to a database server directly but uses a client that corresponds to the used database server. SqlDB sends the commands to the client library; the client library connects to the database and and transfers the commands. This means that a client library must be installed on the computer to make a connection to a database. Under Windows a client is usually a .dll, under Linux an .so and under OS/X a .dylib.<br />
<br />
When the client library is installed properly you can connect to a database server using a TSQLConnection component. Various TSQLConnection components are available for different database servers (see [[SQLdb_Package]]):<br />
<br />
* Firebird/Interbase: [[TIBConnection]]<br />
* MS SQL Server: [[TMSSQLConnection]] (available since FPC 2.6.1)<br />
* MySQL v4.0: [[TMySQL40Connection]] <br />
* MySQL v4.1: [[TMySQL41Connection]] <br />
* MySQL v5.0: [[TMySQL50Connection]] <br />
* MySQL v5.1: [[TMySQL51Connection]] (available since FPC version 2.5.1<br />
* MySQL v5.5: [[TMySQL55Connection]] (available since Lazarus 1.0.8/FPC version 2.6.2<br />
* MySQL v5.6: [[TMySQL56Connection]] (available in Lazarus 1.2.4/FPC version 2.6.4<br />
* ODBC: [[TODBCConnection]] (see [[ODBCConn#TODBCConnection]])<br />
* Oracle: [[TOracleConnection]] (see [[Oracle]])<br />
* PostgreSQL: [[TPQConnection]] (see [[postgresql#SQLDB]])<br />
* Sqlite3: [[TSQLite3Connection]] (available since FPC version 2.2.2, see [[SQLite#Built-in_SQLDB]]) <br />
* Sybase ASE: [[TSybaseConnection]] (available since FPC 2.6.1, see [[Lazarus_Database_Overview#Lazarus_and_MSSQL.2FSybase|Lazarus and MSSQL/Sybase]])<br />
<br />
Note for MySQL - There are many differences between the client versions to the extent that the clients and connections cannot be interchanged. If a MySQL client library version 4.1 is installed, you have to use a TMySQL41Connection. This is not related to the MySQL server; using the MySQL 4.1 client library you can probably connect to a MySQL 5.0 server (see MySQL documentation regarding what combinations are supported).<br />
<br />
Although details differ for the various databases, in general you need to set four properties to connect to a database server: <br />
<br />
* the server name or IP address<br />
* the name of the database<br />
* the username <br />
* the password<br />
<br />
When these properties are set, you can create a connection with the 'open' method. If the connection fails, a EDatabaseError exception is thrown. Use the property 'connected' to test if a connection has been made with the database server. Use the 'close' method to end the connection with the server.<br />
<br />
<syntaxhighlight lang=pascal><br />
Program ConnectDB;<br />
<br />
{$mode objfpc}{$H+}<br />
<br />
uses<br />
IBConnection;<br />
<br />
function CreateConnection: TIBConnection;<br />
begin<br />
result := TIBConnection.Create(nil);<br />
result.Hostname := 'localhost';<br />
result.DatabaseName := '/opt/firebird/examples/employee.fdb';<br />
result.UserName := 'sysdba';<br />
result.Password := 'masterkey';<br />
end;<br />
<br />
var <br />
AConnection : TIBConnection;<br />
<br />
begin<br />
AConnection := CreateConnection;<br />
AConnection.Open;<br />
if Aconnection.Connected then<br />
writeln('Successful connect!')<br />
else<br />
writeln('This is not possible, because if the connection failed, ' +<br />
'an exception should be raised, so this code would not ' +<br />
'be executed');<br />
AConnection.Close;<br />
AConnection.Free;<br />
end.<br />
</syntaxhighlight><br />
<br />
If an exception is thrown, read the error message carefully. It may be that the database server is not running, the user name or password are incorrect or the database name or IP address are typed incorrectly. If the error message states that the client library cannot be found, then check if the client is installed correctly. Often the error message states literally the name of the file looked for.<br />
<br />
== How to execute direct queries/make a table? ==<br />
<br />
SqlDB - the name says it all - only works with database server that make use of SQL. SQL stands for 'Structured Query Language' SQL is a language developed to allow working with relational databases. Virtually every database system has its own dialect, but a large number of SQL statements are the same for all database systems.<br />
<br />
In FPC, there is a difference between:<br />
* SQL statements that return information (a dataset). For this, you have to use the TSQLQuery component; see [[#How to read data from a table?]]. <br />
* statements that do not return information but do something else, e.g. update data. For this, you may also use the 'ExecuteDirect' method of a TSQLConnection. (You can also use this if you get a dataset back but are not interested in the results, e.g. in a selectable stored procedure).<br />
<br />
Most database system execute SQL statements within a transaction. If you want changes made within a transaction available in other transactions, or have those changes available even after closing the transaction(!), then you have to 'commit' the transaction. <br />
<br />
To support transactions Sqldb contains the TSQLTransaction component. A SQL statement that is executed by Sqldb must always be executed within a transaction, even if the database system does not support transactions. Also, there are database systems that do support transaction for which TSQLConnection does not (yet) support transaction. Even then, you must use the TSQLTransaction component.<br />
<br />
To use <tt>TSQLConnection.ExecuteDirect</tt> to execute a SQL statement you must specify which 'Transaction' must be used. In turn, to use TSQLTransaction you must specify which TSQLConnection component must be used.<br />
<br />
The following example creates a table 'TBLNAMES' with fields 'NAME' and 'ID' and inserts two records. This time using SQLite. The used SQL statements are not explained. For more information about the SQL statements, their use and syntax, please refer to the database system documentation. Note that this example does not attempt to catch any errors, thats a bad thing! Look into [https://www.freepascal.org/docs-html/current/ref/refch17.html#x226-24800017 Exceptions].<br />
<br />
<syntaxhighlight lang=pascal><br />
program CreateTable;<br />
{$mode objfpc} {$ifdef mswindows}{$apptype console}{$endif}<br />
uses<br />
sqldb, sqlite3conn; <br />
<br />
var <br />
AConnection : TSQLite3Connection;<br />
ATransaction : TSQLTransaction;<br />
<br />
begin<br />
AConnection := TSQLite3Connection.Create(nil);<br />
AConnection.DatabaseName := 'test_dbase';<br />
<br />
ATransaction := TSQLTransaction.Create(AConnection);<br />
AConnection.Transaction := ATransaction;<br />
AConnection.Open;<br />
ATransaction.StartTransaction;<br />
AConnection.ExecuteDirect('create table TBLNAMES (ID integer, NAME varchar(40));'); <br />
<br />
ATransaction.Commit;<br />
<br />
ATransaction.StartTransaction;<br />
AConnection.ExecuteDirect('insert into TBLNAMES (ID,NAME) values (1,''Name1'');'); <br />
AConnection.ExecuteDirect('insert into TBLNAMES (ID,NAME) values (2,''Name2'');'); <br />
ATransaction.Commit; <br />
AConnection.Close;<br />
ATransaction.Free; <br />
AConnection.Free;<br />
end. </syntaxhighlight><br />
<br />
== How to read data from a table? ==<br />
Use the TSQLQuery component to read data from a table. A TSQLQuery component must be connected to a TSQLConnection component and a TSQLTransaction component to do its work. Setting the TSQLConnection and TSQLTransaction is discussed in [[#How to connect to a database server? ]] and [[#How to execute direct queries/make a table?]]. <br />
<br />
When the TSQLConnection, TSQLTransaction and TSQLQuery are connected, then TSQLQuery needs to be further configured to work. TSQLQuery has a 'SQL' property containing a TStrings object. The 'SQL' property contains a SQL statement that must be executed. If all data from a table <tt>tablename</tt> must be read, then set the 'SQL' property to:<br />
<syntaxhighlight lang="sql">'SELECT * FROM tablename;'</syntaxhighlight>.<br />
<br />
Use 'open' to read the table from the server and put the data in the TSQLQuery dataset. The data can be accessed through TSQLQuery until the query is closed using 'close'.<br />
<br />
TSQLQuery is a subclass of TDataset. TDataset has a 'Fields' collection that contains all columns of the table. The TDataset also keeps track of the current record. Use 'First', 'Next', 'Prior' and 'Last' to change the current record. 'Bof' returns 'True' if the first record is reached, and 'Eof' returns 'True' if the last record is reached. To read the value of a field in the current record, first find the right 'TField' object and then use 'AsString', 'AsInteger', etc.<br />
<br />
=== Example: reading data from a table ===<br />
Below is an example that displays all values of the table as it was made in CreateTable example above. Copy the test_database file into the ShowData working directory. Note, again, no error checking has taken place !<br />
<br />
<syntaxhighlight lang=pascal><br />
Program ShowData;<br />
{$mode objfpc} {$ifdef mswindows}{$apptype console}{$endif}<br />
uses<br />
DB, Sysutils, sqldb, sqlite3conn;<br />
<br />
var<br />
AConnection : TSQLConnection;<br />
ATransaction : TSQLTransaction;<br />
Query : TSQLQuery;<br />
<br />
begin<br />
AConnection := TSQLite3Connection.Create(nil);<br />
ATransaction := TSQLTransaction.Create(AConnection);<br />
AConnection.Transaction := ATransaction;<br />
AConnection.DatabaseName := 'test_dbase';<br />
Query := TSQLQuery.Create(nil);<br />
Query.SQL.Text := 'select * from tblNames';<br />
Query.Database := AConnection;<br />
Query.Open;<br />
while not Query.Eof do<br />
begin<br />
Writeln('ID: ', Query.FieldByName('ID').AsInteger, 'Name: ' +<br />
Query.FieldByName('Name').AsString);<br />
Query.Next;<br />
end;<br />
Query.Close;<br />
AConnection.Close;<br />
Query.Free;<br />
ATransaction.Free;<br />
AConnection.Free;<br />
end.<br />
</syntaxhighlight><br />
<br />
(The code above of course is not quite finished, it misses 'try...finally' blocks. However, the above code intends to show the database code and thus the finishing touches are left out.)<br />
Please note that 'TSQLTransaction.StartTransaction' is not used. This is not necessary. When TSQLQuery is opened, the SQL statement is executed and if no transaction is available then a transaction is automatically started. The programmer does not need to start the transaction explicitly.<br />
The same applies for the connection maintained by TSQLConnection. The connection is opened as needed, the line 'Aconnection.Open' is not really required.<br />
If a TSQLTransaction is destroyed, an automatic 'rollback' will be executed. '''Possible changes to data contained in the transaction will be lost.'''<br />
<br />
=== Why does TSQLQuery.RecordCount always return 10? ===<br />
To count the records in a dataset, use '.RecordCount'. However, notice that '.RecordCount' shows the number of records that is already loaded from the server. For performance reasons, SqlDB does not read all records when opening TSQLQuery by default, only the first 10. Only when the eleventh record is accessed will the next set of 10 records be loaded, etc. Using '.Last', all records will be loaded. <br />
<br />
When you want to know the real number of records on the server you can first call '.Last' and then call '.RecordCount'. <br />
<br />
An alternative is available. The number of records returned by the server is set by the '.PacketRecords' property. The default value is 10; if you make it -1 then all records will be loaded at once.<br />
<br />
In current stable FPC, '.RecordCount' does not take filters into account, i.e. it shows the unfiltered total.<br />
<br />
If you need the exact number of records, it often is a better idea to directly query the number of records in a query using another SQL query, but you would have to do that in the same transaction, as other transactions may have changed the number of records in the meanwhile.<br />
<br />
=== Lazarus ===<br />
Lazarus has various components to show data from a TDataset on a form. Instead of a While-loop and Writeln statements as used above, you can use the components to show the data in a table. Place the right TSQLConnection, TSQLTransaction and TSQLQuery components on a form, then connect them and set them properly. In addition you will need a TDatasource; set the 'TDatasource.Dataset' property to the TSQLQuery component you used. ('''Note''' do not set the 'TSQLQuery.Datasource' property to the TDatasource compnent you used. The 'TSQLQuery.Datasource' property is used only in master-detail tables - see [[MasterDetail]]) Subsequently you may put a TDBGrid onto the form and set the 'Datasource' property of the grid to the TDatasource component you added before.<br />
<br />
To see if it all works, set the 'Connected' property of the TSQLConnection to 'True' in the Lazarus IDE. The IDE will try to connect to the database server immediately. If this works you can set the 'TSQLQuery.Active' property to 'True'. If everything is right, you will see - within the IDE - all data from the table immediately on the screen.<br />
<br />
== How to change data in a table? ==<br />
To change the data in a record (or records), the general process is get TSQLQuery to search for the records you wish to change, make the changes there and then push them back to the database. The [[TDataSet]] (from which TSQLQuery is derived) must be set to edit mode. To enter edit mode call the '.Edit', '.Insert' or '.Append' methods. Use the '.Edit' method to change the current record. Use '.Insert' to insert a new record before the current record. Use '.Append' to insert a new record at the end of the table. In edit mode you can change field values through the 'Fields' property. Use 'Post' to validate the new data, if the data is valid then the edit mode is left. If you move to another record - for example by using '.Next' - and the dataset is in edit mode, then first '.Post' is called. Use '.Cancel' to discard all changes you made since the last '.Post' call and leave the edit mode.<br />
<br />
<syntaxhighlight lang=pascal><br />
Query.Edit;<br />
Query.FieldByName('NAME').AsString := 'Edited name';<br />
Query.Post;</syntaxhighlight><br />
<br />
The above is not the complete story yet. TSQLQuery is derived from TBufDataset which makes use of buffered updates. Buffered update means that after you called 'Post' the changes in the dataset are visible immediately, but they are not sent to the database server. What does happen is that the changes are maintained in a change log. When the '.ApplyUpdates' method is called, then all changes in the change log are sent to the database. Only then will database server know of the changes. The changes are sent to the server within a transaction of TSQLTransaction. Make sure to properly set the transaction before 'ApplyUpdates'. After applying the updates, a commit must be executed to save the changes on the database server.<br />
<br />
The below is an example of changing the data in a table, sending the changes to the server and committing the transaction. Again, no error checking, again, thats bad!<br />
<br />
<syntaxhighlight lang=pascal><br />
Program EditData;<br />
{$mode objfpc} {$ifdef mswindows}{$apptype console}{$endif}<br />
uses<br />
db, sqldb, sqlite3conn;<br />
var <br />
AConnection : TSQLConnection;<br />
ATransaction : TSQLTransaction;<br />
Query : TSQLQuery;<br />
<br />
begin<br />
AConnection := TSQLite3Connection.Create(nil);<br />
ATransaction := TSQLTransaction.Create(AConnection);<br />
AConnection.Transaction := ATransaction;<br />
AConnection.DatabaseName := 'test_dbase';<br />
Query := TSQLQuery.Create(nil);<br />
Query.DataBase := AConnection;<br />
Query.SQL.Text := 'select * from tblNames where ID = 2';<br />
Query.Open;<br />
Query.Edit;<br />
Query.FieldByName('NAME').AsString := 'Name Number 2';<br />
Query.Post;<br />
Query.UpdateMode := upWhereAll; // defined in db<br />
Query.ApplyUpdates;<br />
ATransaction.Commit;<br />
Query.Free;<br />
ATransaction.Free;<br />
AConnection.Free;<br />
end. <br />
</syntaxhighlight><br />
<br />
The actual works starts with the SQL statement "select * from tblNames where ID = 2" identifying the record (or records) you wish to change. If you leave out the "where ID = 2" bit, the TSQLQuery apparently sets ID (and other integer fields?) to 1. And therefore will operate on lines where ID=1 only. For a discussion of 'UpdateMode' continue reading.<br />
<br />
== How does SqlDB send the changes to the database server? ==<br />
<br />
In the code example in [[#How to change data in a table?]], you will find the line<br />
<syntaxhighlight lang=pascal>Query.UpdateMode := upWhereAll;</syntaxhighlight><br />
without explanation of what it does. The best way to find out what that line does is to leave it out. If you leave out the statement and the followed this howto precisely, then you will receive the following error message:<br />
No update query specified and failed to generate one. (No fields for inclusion in where statement found)<br />
To understand what went wrong, you must understand how changes are sent to the database server. The only way to get data in a SQL server is by executing SQL queries. SQL has three types of queries for three different ways of manupulating a record. To create a new record, change or delete a record insert, update and delete statements are executed respectively. An update statement may be as follows:<br />
<syntaxhighlight lang="sql">update TBLNAMES set NAME='Edited name' where ID=1;</syntaxhighlight><br />
To send a change to the database server, Sqldb must assemble an update query. To assemble the query, three things are needed:<br />
; The name of the table : The table name is retrieved from parsing the select query, although this doesn't always work. <br />
; <tt>UPDATE</tt> or <tt>INSERT</tt> clause : These contain the fields that must be changed.<br />
; <tt>WHERE</tt> clause : This contains the fields that determine which records should be changed.<br />
<br />
Every field (each ''TField'' in ''Fields'') has a ProviderFlags property. Only fields with '''pfInUpdate''' in ''ProviderFlags'' will be used in the update or insert cluase of a query. By default all fields have ''pfInUpdate'' set in their ''ProviderFlags'' property.<br />
<br />
Which fields are used in the <tt>WHERE</tt> clause depends on the ''UpdateMode'' property of the query and the ''ProviderFlags'' property of the fields. Fields with ''pfInkey'' in their ''ProviderFlags'' are always used in the <tt>WHERE</tt> clause. A field will have the ''pfInKey'' flag set automatically if the field is part of the primary key of the table and 'TSQLQuery.UsePrimaryKeyAsKey' returns 'True'.<br />
<br />
The default value for ''UpdateMode'' of the query is ''upWhereKeyOnly''. In this update mode only fields with ''pfInkey'' in their ''ProviderFlags'' property are used in the <tt>WHERE</tt> clause. If none of the fields have their ''pfInKey'' flag set, then no fields are available for the <tt>WHERE</tt> clause and the error message from the beginning of this section will be returned. You can solve the issue by:<br />
* Adding a primary key to the table and set ''TSQLQuery.UsePrimaryKeyAsKey'' to 'True', or<br />
* Setting the ''pfInkey'' flag for one or more fields in code.<br />
<br />
The '''UpdateMode''' property knows two more possible values. 'upWhereAll' can be used to add all fields with the 'pfInWhere' flag set to the <tt>WHERE</tt> clause. By default all fields have this flag set. 'upWhereChanged' can be used to add only those fields that have the 'pfInWhere' flag set '''and''' that are changed in the current record.<br />
<br />
==How to handle Errors==<br />
Run time errors are unavoidable, disks may fill up, necessary libraries or helper apps may not be available, things go wrong and we need to allow for that.<br />
The FPC detects and handles run time errors quite well. It usually gives you a concise and reasonable explanation of what went wrong. However, you will want<br />
to monitor and handle errors yourself for a number of reasons -<br />
* You probably don't want the programme to teminate at the first sign of trouble.<br />
* If we do keep going, lets make sure any memory allocated in the problem area is recovered, we don't want any memory leaks.<br />
* If we are going to go under however, lets give the user a context sensitive explanation.<br />
<br />
The following bit of code is based on the above examples but this time it DOES check for errors in critical places. Key is the try...finally...end and try...except...end blocks. You can test it by doing things like uninstalling SQLite3, putting a dummy file in place of the test_dbase database and so on.<br />
<br />
<syntaxhighlight lang=pascal><br />
program DemoDBaseWithErrors;<br />
{$mode objfpc} {$ifdef mswindows}{$apptype console}{$endif}<br />
uses<br />
DB, Sysutils, sqldb, sqlite3conn;<br />
var<br />
Connect : TSQLite3Connection;<br />
Trans : TSQLTransaction;<br />
<br />
<br />
procedure WriteTable (Command : string);<br />
begin<br />
Connect.ExecuteDirect(Command);<br />
Trans.Commit;<br />
end;<br />
<br />
procedure ReadTable ();<br />
var<br />
Query : TSQLQuery;<br />
Count : smallint;<br />
begin<br />
Count := 0;<br />
try<br />
Query := TSQLQuery.Create(nil);<br />
Query.DataBase := Connect;<br />
Query.SQL.Text:= 'select * from tblNames';<br />
Query.Open; // This will also open Connect<br />
while not Query.EOF do begin<br />
writeln('ID: ', Query.FieldByName('ID').AsInteger, ' Name: ' +<br />
Query.FieldByName('Name').AsString);<br />
Query.Next;<br />
Count := Count + 1;<br />
end;<br />
finally<br />
Query.Close;<br />
Query.Free;<br />
end;<br />
writeln('Found a total of ' + InttoStr(Count) + ' lines.');<br />
end;<br />
<br />
procedure FatalError(ClassName, Message, Suggestion : string);<br />
begin<br />
writeln(ClassName);<br />
writeln(Message);<br />
writeln(Suggestion);<br />
Connect.Close; // Its possibly silly worrying about freeing<br />
Trans.free; // if we are going to call halt() but its<br />
Connect.Free; // a demo, alright ?<br />
halt();<br />
end;<br />
<br />
begin<br />
Connect := TSQLite3Connection.Create(nil);<br />
Trans := TSQLTransaction.Create(Connect);<br />
Connect.Transaction := Trans;<br />
Connect.DatabaseName := 'test_dbase';<br />
try<br />
if not fileexists(Connect.DatabaseName) then begin<br />
Connect.Open; // give EInOutError if (eg) SQLite not installed<br />
Trans.StartTransaction;<br />
WriteTable('create table TBLNAMES (ID integer Primary Key, NAME varchar(40));');<br />
Trans.Commit;<br />
end;<br />
Connect.open;<br />
Trans.StartTransaction;<br />
WriteTable('insert into TBLNAMES (NAME) values (''AName1'');');<br />
WriteTable('insert into TBLNAMES (NAME) values (''AName2'');');<br />
except<br />
on E : EDatabaseError do<br />
FatalError(E.ClassName, E.Message, 'Does the file contain the correct database ?');<br />
on E : EInOutError do<br />
FatalError(E.ClassName, E.Message, 'Have you installed SQLite (and dev package)?');<br />
on E : Exception do<br />
FatalError(E.ClassName, E.Message, 'Something really really bad happened.');<br />
end;<br />
ReadTable();<br />
Connect.Close;<br />
Trans.Free;<br />
Connect.Free;<br />
end. <br />
</syntaxhighlight><br />
<br />
== How to execute a query using TSQLQuery? ==<br />
Next to statements that return a dataset (see [[#How to read data from a table?]]) SQL has statements that do not return data. For example <tt>INSERT</tt>, <tt>UPDATE</tt> and <tt>DELETE</tt> statements do not return data. These statements can be executed using ''[[#How to execute direct queries/make a table?|TSQLConnection.ExecuteDirect]]'', but TSQLQuery can also be used. If you do not expect return data use ''TSQLQuery.ExecSQL'' instead of ''TSQLQuery.Open''. As mentioned earlier, use ''TSQLQuery.Open'' to open the dataset returned by the SQL statement. <br />
<br />
The following procedure creates a table and inserts two records using TSQLQuery.<br />
<br />
<syntaxhighlight lang=pascal><br />
procedure CreateTable;<br />
<br />
var <br />
Query : TSQLQuery;<br />
<br />
begin<br />
Query := TSQLQuery.Create(nil);<br />
try<br />
Query.Database := AConnection;<br />
<br />
Query.SQL.Text := 'create table TBLNAMES (ID integer, NAME varchar(40));';<br />
Query.ExecSQL;<br />
<br />
Query.SQL.Text := 'insert into TBLNAMES (ID,NAME) values (1,''Name1'');';<br />
Query.ExecSQL;<br />
<br />
Query.SQL.Text := 'insert into TBLNAMES (ID,NAME) values (2,''Name2'');';<br />
Query.ExecSQL;<br />
finally<br />
Query.Free;<br />
end;<br />
end;</syntaxhighlight><br />
<br />
== How to use parameters in a query? ==<br />
In the code example of [[#How to execute a query using TSQLQuery?]] the same query is used twice, only the values to be inserted differ. A better way to do this is by using parameters in the query. <br />
<br />
The syntax of parameters in queries is different per database system, but the differences are handled by TSQLQuery. Replace the values in the query with a colon followed by the name of the parameter you want to use. For example:<br />
<syntaxhighlight lang=pascal>Query.SQL.Text := 'insert into TBLNAMES (ID,NAME) values (:ID,:NAME);';</syntaxhighlight><br />
<br />
This query will create two parameters: 'ID' and 'NAME'.<br />
To determine the parameters, the query is parsed at the moment the text of ''TSQLQuery.SQL'' is assigned or changed. All existing parameters will be removed and the new parameters will be added to the 'TSQLQuery.Params' property. Assigning a value to a parameter is similar to assigning a value to a field in the dataset:<br />
<br />
<syntaxhighlight lang=pascal><br />
Query.Params.ParamByName('Name').AsString := 'Name1';<br />
</syntaxhighlight><br />
<br />
You can't tell from the query what kind of data must be stored in the parameter. The data type of the parameter is determined at the moment a value is first assigned to the parameter. By assigning a value using '.AsString', the parameter is assigned the data type 'ftString'. You can determine the data type directly by setting the 'DataType' property. If an incorrect datatype is assigned to the parameter, then problems will occur during opening or executing the query.<br />
See [[Database field type]] for more information on data types.<br />
<br />
=== Select query ===<br />
<br />
An example of a select query with parameters would be to change something like this:<br />
<br />
<syntaxhighlight lang=pascal><br />
Query.SQL.Text := 'select ID,NAME from TBLNAMES where NAME = '''+Edit1.Text+''' ORDER BY NAME ';<br />
</syntaxhighlight><br />
<br />
to something like this:<br />
<br />
<syntaxhighlight lang=pascal><br />
Query.SQL.Text := 'select ID,NAME from TBLNAMES where NAME = :NAMEPARAM ORDER BY NAME ';<br />
Query.Params.ParamByName('NAMEPARAM').AsString := Edit1.Text;<br />
</syntaxhighlight><br />
<br />
=== Example ===<br />
<br />
The following example creates the same table as the previous example, but now parameters are used:<br />
<br />
<syntaxhighlight lang=pascal><br />
procedure CreateTableUsingParameters;<br />
<br />
var <br />
Query : TSQLQuery;<br />
<br />
begin<br />
Query := TSQLQuery.Create(nil);<br />
try<br />
Query.Database := AConnection;<br />
<br />
Query.SQL.Text := 'create table TBLNAMES (ID integer, NAME varchar(40));';<br />
Query.ExecSQL;<br />
<br />
Query.SQL.Text := 'insert into TBLNAMES (ID,NAME) values (:ID,:NAME);';<br />
Query.Prepare;<br />
<br />
Query.Params.ParamByName('ID').AsInteger := 1;<br />
Query.Params.ParamByName('NAME').AsString := 'Name1';<br />
Query.ExecSQL;<br />
<br />
Query.Params.ParamByName('ID').AsInteger := 2;<br />
Query.Params.ParamByName('NAME').AsString := 'Name2';<br />
Query.ExecSQL;<br />
<br />
//Query.UnPrepare; // no need to call this; should be called by Query.Close<br />
Query.Close;<br />
finally<br />
Query.Free;<br />
end;<br />
end;<br />
</syntaxhighlight><br />
<br />
Notice that this example requires more code than the example without the parameters. Then what is the use of using parameters? <br />
<br />
Speed is one of the reasons. The example with parameters is faster, because the database server parses the query only once (in the .Prepare statement or at first run). <br />
<br />
Another reason to use prepared statements is prevention of [http://en.wikipedia.org/wiki/SQL_injection SQL-injection] (see also [[Secure programming]]. <br />
<br />
Finally, in some cases it just simplifies coding.<br />
<br />
== Troubleshooting: TSQLConnection logging ==<br />
<br />
You can let a TSQLConnection log what it is doing. This can be handy to see what your Lazarus program sends to the database exactly, to debug the database components themselves and perhaps to optimize your queries.<br />
NB: if you use prepared statements/parametrized queries (see section above), the parameters are often sent in binary by the TSQLConnection descendent (e.g. TIBConnection), so you can't just copy/paste the logged SQL into a database query tool.<br />
Regardless, connection logging can give a lot of insight in what your program is doing.<br />
<br />
Alternatives are: <br />
<br />
# you can use the debugger to step through the database code if you have built FPC (and Lazarus) with debugging enabled. <br />
# if you use ODBC drivers (at least on Windows) you could enable tracelog output in the ODBC control panel.<br />
# many databases allow you to monitor all statements sent to it from a certain IP address/connection.<br />
<br />
If you use TSQLConnection logging, two things are required:<br />
<br />
# indicate which event types your TSQLConnection should log<br />
# point TSQLConnection at a function that receives the events and processes them (logs them to file, prints them to screen, etc.).<br />
That function must be of type TDBLogNotifyEvent (see sqldb.pp), so it needs this signature:<br />
<br />
<syntaxhighlight lang=pascal><br />
TDBLogNotifyEvent = Procedure (Sender : TSQLConnection; EventType : TDBEventType; Const Msg : String) of object;<br />
</syntaxhighlight><br />
<br />
=== FPC (or: the manual way) ===<br />
<br />
A code snippet can illustrate this:<br />
<br />
<syntaxhighlight lang=pascal><br />
uses<br />
...<br />
TSQLConnection, //or a child object like TIBConnection, TMSSQLConnection<br />
...<br />
var<br />
type <br />
TMyApplication = class(TCustomApplication); //this is our application that uses the connection<br />
...<br />
private<br />
// This example stores the logged events in this stringlist:<br />
FConnectionLog: TStringList;<br />
...<br />
protected<br />
// This procedure will receive the events that are logged by the connection:<br />
procedure GetLogEvent(Sender: TSQLConnection; EventType: TDBEventType; Const Msg : String);<br />
...<br />
procedure TMyApplication.GetLogEvent(Sender: TSQLConnection;<br />
EventType: TDBEventType; const Msg: String);<br />
// The procedure is called by TSQLConnection and saves the received log messages<br />
// in the FConnectionLog stringlist<br />
var<br />
Source: string;<br />
begin<br />
// Nicely right aligned...<br />
case EventType of<br />
detCustom: Source:='Custom: ';<br />
detPrepare: Source:='Prepare: ';<br />
detExecute: Source:='Execute: ';<br />
detFetch: Source:='Fetch: ';<br />
detCommit: Source:='Commit: ';<br />
detRollBack: Source:='Rollback:';<br />
else Source:='Unknown event. Please fix program code.';<br />
end;<br />
FConnectionLog.Add(Source + ' ' + Msg);<br />
end;<br />
<br />
...<br />
// We do need to tell our TSQLConnection what to log:<br />
FConnection.LogEvents:=LogAllEvents; //= [detCustom, detPrepare, detExecute, detFetch, detCommit, detRollBack]<br />
// ... and to which procedure the connection should send the events:<br />
FConnection.OnLog:=@Self.GetLogEvent;<br />
...<br />
// now we can use the connection and the FConnectionLog stringlist will fill with log messages.<br />
</syntaxhighlight><br />
<br />
You can also use TSQLConnection's GlobalDBLogHook instead to log everything from multiple connections.<br />
<br />
=== Lazarus (or: the quick way) ===<br />
<br />
Finally, the description above is the FPC way of doing things as indicated in the introduction; if using Lazarus, a quicker way is to assign an event handler to the TSQLConnection's OnLog event.<br />
<br />
== See also ==<br />
<br />
* [[Working With TSQLQuery]]</div>Aribenhttps://wiki.freepascal.org/How_to_write_in-memory_database_applications_in_Lazarus/FPC/jaHow to write in-memory database applications in Lazarus/FPC/ja2024-03-26T22:12:28Z<p>Ariben: Created page with "{{How_to_write_in-memory_database_applications_in_Lazarus/FPC}} {{Infobox databases/ja}} == イントロダクション == There are certain circumstances when in-memory dat..."</p>
<hr />
<div>{{How_to_write_in-memory_database_applications_in_Lazarus/FPC}}<br />
{{Infobox databases/ja}}<br />
<br />
== イントロダクション ==<br />
<br />
There are certain circumstances when in-memory datasets make sense. If you need a fast, single-user, non mission-critical, non SQL database, without need for transactions, [[TMemDataset]] could suit your needs.<br />
<br />
Some benefits are: <br />
* Fast execution. Since all processing is done in memory, no data is saved on hard disk until explicitly asked. Memory is surely faster than hard disk.<br />
* No need for external libraries (no .so or .dll files), no need for server installation<br />
* Code is multiplatform and can be compiled on any OS instantly<br />
* Since all programming is done in Lazarus/FPC, such applications are easier for maintenance. Instead of constantly switching from back-end programming to front-end programming, by using MemDatasets you can concentrate on your Pascal code.<br />
<br />
{{Note|later on in this article, BufDataset is introduced. [[TBufDataset]] often is a better choice than [[TMemDataset]] }}<br />
<br />
I will illustrate how to program relational non-SQL memory databases, focusing on enforcing relation integrity and filtering, simulating auto-increment primary fields and similar. <br />
<br />
This page shares with you what I have learned experimenting with TMemDatasets. There might be some other, more efficient way to do this. If so, please, feel free to contribute to this document for the benefit of the Lazarus/FPC community.<br />
<br />
The memds unit provides TMemDataset, so you will need to add that to your uses clause.<br />
<br />
== Saving MemDatasets to persistent files ==<br />
<br />
In the [[Interface|interface]] part of your code, declare an array type for storing information about all the TMemDataSets that you want to make persistent at the end of a session and restore at the beginning of the next session. You have to declare a variable of type TSaveTables, too.<br />
<br />
I also use a global variable vSuppressEvents of type boolean, for suppressing Dataset events used for referential integrity enforcement, during data restore.<br />
<br />
You get this:<br />
<br />
<syntaxhighlight lang=pascal><br />
type<br />
TSaveTables=array[1..15] of TMemDataset; <br />
var<br />
//Global variable that holds tables for saving/restoring session<br />
vSaveTables:TSaveTables; <br />
//Suppress events flag variables. Used during data loading from files.<br />
vSuppressEvents:Boolean;<br />
</syntaxhighlight> <br />
<br />
Instead of using global variables like I did, you could make them a property of the main form, also.<br />
TMemDataset has a way to natively store data to persistent file: the SaveToFile method. But, you could rather choose to save data to [[CSV]] files for easier external post processing. Therefore, I will combine both ways into same procedures.<br />
I define a constant cSaveRestore in the Interface part, by which I can define whether data will be stored and loaded as native MemDataset files or CSV files.<br />
<br />
<syntaxhighlight lang=pascal><br />
const<br />
//Constant cSaveRestore determines the way for saving and restoring of MemDatasets to persistent files<br />
cSaveRestore=0; //0=MemDataset native way, 1=saving and restoring from CSV <br />
</syntaxhighlight><br />
<br />
Now, you can save MemDatasets on FormClose event and load them on FormCreate event. Instantiate elements of the array of MemDatasets on the FormCreate event, too.<br />
<br />
<syntaxhighlight lang=pascal><br />
procedure TMainForm.FormCreate(Sender: TObject);<br />
begin<br />
//List of tables to be saved/restored for a session<br />
vSaveTables[1]:=Products;<br />
vSaveTables[2]:=Boms;<br />
vSaveTables[3]:=Stocks;<br />
vSaveTables[4]:=Orders;<br />
vSaveTables[5]:=BomCalculationProducts;<br />
vSaveTables[6]:=BomCalculationComponents;<br />
vSaveTables[7]:=BomCalculationFooter;<br />
vSaveTables[8]:=BomCalculationProductsMultiple;<br />
vSaveTables[9]:=BomCalculationComponentsMultiple;<br />
vSaveTables[10]:=BomCalculationFooterMultiple;<br />
vSaveTables[11]:=ImportVariants;<br />
vSaveTables[12]:=ImportToTables;<br />
vSaveTables[13]:=ImportToFields;<br />
vSaveTables[14]:=ImportFromTables;<br />
vSaveTables[15]:=ImportFromFields;<br />
//Restore session<br />
RestoreSession;<br />
GetAutoincrementPrimaryFields;<br />
end;</syntaxhighlight><br />
<br />
<syntaxhighlight lang=pascal><br />
procedure TMainForm.FormClose(Sender: TObject; var CloseAction: TCloseAction);<br />
begin<br />
//Save memdatasets to files (to save current session)<br />
SaveSession;<br />
end;</syntaxhighlight><br />
<br />
<syntaxhighlight lang=pascal><br />
procedure RestoreSession;<br />
var<br />
I:Integer;<br />
begin<br />
try<br />
MemoMessages.Append(TimeToStr(Now())+' Starting restoration of previously saved session.');<br />
vSuppressEvents:=True; //Supress events used for referential integrity enforcing<br />
//Disable controls and refresh all datasets<br />
for I:=Low(vSaveTables) to High(vSaveTables) do begin<br />
vSaveTables[I].DisableControls;<br />
vSaveTables[I].Refresh; //Important if dataset was filtered<br />
end;<br />
//Load memdatasets from files (to restore previous session)<br />
for I:=Low(vSaveTables) to High(vSaveTables) do begin<br />
vSaveTables[I].First;<br />
MemoMessages.Append(TimeToStr(Now())+' Starting restoration of table: '+vSaveTables[I].Name);<br />
try<br />
//If data is loaded from a csv file, then table must be deleted first.<br />
if cSaveRestore=1 then begin<br />
MemoMessages.Append(TimeToStr(Now())+' Starting delete of all records in table: '+vSaveTables[I].Name);<br />
//This way of deleting all records is incredibly slow.<br />
{while not vSaveTables[I].EOF do begin<br />
vSaveTables[I].Delete;<br />
end;}<br />
//This method for deleting of all records is much faster<br />
EmptyMemDataSet(vSaveTables[I]);<br />
MemoMessages.Append(TimeToStr(Now())+' All records from table: '+vSaveTables[I].Name+' deleted.');<br />
end;<br />
except<br />
on E:Exception do begin<br />
MemoMessages.Append(TimeToStr(Now())+' Error while deleteing records from table: '+vSaveTables[I].Name +'. '+E.Message);<br />
end;<br />
end;<br />
try<br />
try<br />
MemoMessages.Append(TimeToStr(Now())+' Restoring table: '+vSaveTables[I].Name);<br />
//Check constant for way of saving/restoring data and load saved session<br />
case cSaveRestore of<br />
0:vSaveTables[I].LoadFromFile(vSaveTables[I].Name);<br />
1:LoadFromCsv(vSaveTables[I]);<br />
end;<br />
except<br />
on E:Exception do begin<br />
MemoMessages.Append(TimeToStr(Now())+' Error while restoring table: '+vSaveTables[I].Name +'. '+E.Message);<br />
end;<br />
end;<br />
finally<br />
vSaveTables[I].Active:=True;//Needed because of LoadFromFile method....<br />
end;<br />
MemoMessages.Append(TimeToStr(Now())+' Table: '+vSaveTables[I].Name+' restored.');<br />
end;<br />
finally<br />
vSuppressEvents:=False;<br />
//Refresh all datasets and enable controls<br />
for I:=Low(vSaveTables) to High(vSaveTables) do begin<br />
vSaveTables[I].Refresh; //Needed for tables that are filtered.<br />
vSaveTables[I].EnableControls;<br />
end;<br />
MemoMessages.Append(TimeToStr(Now())+' All tables restored from saved files.');<br />
end;<br />
end;</syntaxhighlight><br />
<br />
<syntaxhighlight lang=pascal><br />
procedure SaveSession;<br />
var<br />
I:Integer;<br />
begin<br />
try<br />
MemoMessages.Append(TimeToStr(Now())+' Starting saving session to persistent files.');<br />
vSuppressEvents:=True;<br />
//Disable controls and refresh all datasets<br />
for I:=Low(vSaveTables) to High(vSaveTables) do begin<br />
vSaveTables[I].DisableControls;<br />
vSaveTables[I].Refresh; //Important if dataset was filtered<br />
end;<br />
//Save session to file<br />
for I:=Low(vSaveTables) to High(vSaveTables) do begin<br />
vSaveTables[I].First;<br />
MemoMessages.Append(TimeToStr(Now())+' Saving table: '+vSaveTables[I].Name);<br />
try<br />
//Check constant for way of saving/restoring data and save session<br />
case cSaveRestore of<br />
0:vSaveTables[I].SaveToFile(vSaveTables[I].Name);<br />
1:SaveToCsv(vSaveTables[I]);<br />
end;<br />
except<br />
on E:Exception do begin<br />
MemoMessages.Append(TimeToStr(Now())+' Error while saving table: '+vSaveTables[I].Name +'. '+E.Message);<br />
end;<br />
end;<br />
MemoMessages.Append(TimeToStr(Now())+' Table: '+vSaveTables[I].Name+' saved.');<br />
end;<br />
finally<br />
vSuppressEvents:=False;<br />
//Refresh all datasets and enable controls<br />
for I:=Low(vSaveTables) to High(vSaveTables) do begin<br />
vSaveTables[I].Refresh; //Needed for tables that are filtered<br />
vSaveTables[I].EnableControls;<br />
end;<br />
MemoMessages.Append(TimeToStr(Now())+' All tables saved to files.');<br />
end;<br />
end;</syntaxhighlight> <br />
<br />
<syntaxhighlight lang=pascal><br />
procedure EmptyMemDataSet(DataSet:TMemDataSet);<br />
var<br />
vTemporaryMemDataSet:TMemDataSet;<br />
vFieldDef:TFieldDef;<br />
I:Integer;<br />
begin<br />
try<br />
//Create temporary MemDataSet<br />
vTemporaryMemDataSet:=TMemDataSet.Create(nil);<br />
//Store FieldDefs to Temporary MemDataSet<br />
for I:=0 to DataSet.FieldDefs.Count-1 do begin<br />
vFieldDef:=vTemporaryMemDataSet.FieldDefs.AddFieldDef;<br />
with DataSet.FieldDefs[I] do begin<br />
vFieldDef.Name:=Name;<br />
vFieldDef.DataType:=DataType;<br />
vFieldDef.Size:=Size;<br />
vFieldDef.Required:=Required;<br />
end;<br />
end;<br />
//Clear existing fielddefs<br />
DataSet.Clear;<br />
//Restore fielddefs<br />
DataSet.FieldDefs:=vTemporaryMemDataSet.FieldDefs;<br />
DataSet.Active:=True;<br />
finally<br />
vTemporaryMemDataSet.Clear;<br />
vTemporaryMemDataSet.Free;<br />
end;<br />
end;</syntaxhighlight><br />
<br />
<syntaxhighlight lang=pascal><br />
procedure LoadFromCsv(DataSet:TDataSet);<br />
var<br />
vFieldCount:Integer;<br />
I:Integer;<br />
begin<br />
try<br />
//Assign SdfDataSetTemporary<br />
with SdfDataSetTemporary do begin<br />
Active:=False;<br />
ClearFields;<br />
FileName:=DataSet.Name+'.txt';<br />
FirstLineAsSchema:=True;<br />
Active:=True;<br />
//Determine number of fields<br />
vFieldCount:=FieldDefs.Count;<br />
end;<br />
//Iterate through SdfDataSetTemporary and insert records into MemDataSet<br />
SdfDataSetTemporary.First;<br />
while not SdfDataSetTemporary.EOF do begin<br />
DataSet.Append;<br />
//Iterate through FieldDefs<br />
for I:=0 to vFieldCount-1 do begin<br />
try<br />
DataSet.Fields[I].Value:=SdfDataSetTemporary.Fields[I].Value;<br />
except<br />
on E:Exception do begin<br />
MemoMessages.Append(TimeToStr(Now())+' Error while setting value for field: '<br />
+DataSet.Name+'.'+DataSet.Fields[I].Name +'. '+E.Message);<br />
end;<br />
end;<br />
end;<br />
try<br />
DataSet.Post;<br />
except<br />
on E:Exception do begin<br />
MemoMessages.Append(TimeToStr(Now())+' Error while posting record to table: '<br />
+DataSet.Name+'.'+E.Message);<br />
end;<br />
end;<br />
SdfDataSetTemporary.Next;<br />
end;<br />
finally<br />
SdfDataSetTemporary.Active:=False;<br />
SdfDataSetTemporary.ClearFields;<br />
end;<br />
end;</syntaxhighlight><br />
<br />
<syntaxhighlight lang=pascal><br />
procedure SaveToCsv(DataSet:TDataSet);<br />
var<br />
myFileName:string;<br />
myTextFile: TextFile;<br />
i: integer;<br />
s: string;<br />
begin<br />
myFileName:=DataSet.Name+'.txt';<br />
//create a new file<br />
AssignFile(myTextFile, myFileName);<br />
Rewrite(myTextFile);<br />
s := ''; //initialize empty string<br />
try<br />
//write field names (as column headers)<br />
for i := 0 to DataSet.Fields.Count - 1 do<br />
begin<br />
s := s + Format('%s,', [DataSet.Fields[i].FieldName]);<br />
end;<br />
Writeln(myTextFile, s);<br />
DataSet.First;<br />
//write field values<br />
while not DataSet.Eof do<br />
begin<br />
s := '';<br />
for i := 0 to DataSet.FieldCount - 1 do<br />
begin<br />
//Numerical fields without quotes, string fields with quotes<br />
if ((DataSet.FieldDefs[i].DataType=ftInteger)<br />
or (DataSet.FieldDefs[i].DataType=ftFloat)) then<br />
s := s + Format('%s,', [DataSet.Fields[i].AsString])<br />
else<br />
s := s + Format('"%s",', [DataSet.Fields[i].AsString]);<br />
end;<br />
Writeln(myTextfile, s);<br />
DataSet.Next;<br />
end;<br />
finally<br />
CloseFile(myTextFile);<br />
end;<br />
end;</syntaxhighlight><br />
<br />
== Autoincrement Primary Keys ==<br />
<br />
Autoincrement field type is not supported by MemDataset. Nevertheless, you can imitate it by using Integer field type and providing a calculator for autoincrement fields.<br />
We need global variables or public properties for storing current autoincrement field value. I prefer global variables, declared in Interface part.<br />
<br />
<syntaxhighlight lang=pascal><br />
var<br />
//Global variables used for calculation of autoincrement primary key fields of MemDatasets<br />
vCurrentId:Integer=0;<br />
vProductsId:Integer=0;<br />
vBomsId:Integer=0;<br />
vBomCalculationProductsId:Integer=0;<br />
vBomCalculationComponentsId:Integer=0;<br />
vBomCalculationFooterId:Integer=0;<br />
vBomCalculationProductsMultipleId:Integer=0;<br />
vBomCalculationComponentsMultipleId:Integer=0;<br />
vBomCalculationFooterMultipleId:Integer=0;<br />
vStocksId:Integer=0;<br />
vOrdersId:Integer=0;<br />
vImportVariantsId:Integer=0;<br />
vImportToTablesId:Integer=0;<br />
vImportToFieldsId:Integer=0;<br />
vImportFromTablesId:Integer=0;<br />
vImportFromFieldsId:Integer=0;</syntaxhighlight><br />
Then we have a procedure for autoincrement field values calculation:<br />
<br />
<syntaxhighlight lang=pascal><br />
procedure GetAutoincrementPrimaryFields;<br />
var<br />
I:Integer;<br />
vId:^Integer;<br />
begin<br />
try<br />
MemoMessages.Lines.Append(TimeToStr(Now())+' Getting information about autoincrement fields');<br />
vSuppressEvents:=True;<br />
//Disable controls and refresh all datasets<br />
for I:=Low(vSaveTables) to High(vSaveTables) do begin<br />
vSaveTables[I].DisableControls;<br />
vSaveTables[I].Refresh; //Important if dataset was filtered<br />
end;<br />
for I:=Low(vSaveTables) to High(vSaveTables) do begin<br />
with vSaveTables[I] do begin<br />
//Use appropriate global variable<br />
case StringToCaseSelect(Name,<br />
['Products','Boms','Stocks','Orders',<br />
'BomCalculationProducts','BomCalculationComponents','BomCalculationFooter',<br />
'BomCalculationProductsMultiple','BomCalculationComponentsMultiple','BomCalculationFooterMultiple',<br />
'ImportVariants','ImportToTables','ImportToFields','ImportFromTables','ImportFromFields']) of<br />
0:vId:=@vProductsId;<br />
1:vId:=@vBomsId;<br />
2:vId:=@vStocksId;<br />
3:vId:=@vOrdersId;<br />
4:vId:=@vBomCalculationProductsId;<br />
5:vId:=@vBomCalculationComponentsId;<br />
6:vId:=@vBomCalculationFooterId;<br />
7:vId:=@vBomCalculationProductsMultipleId;<br />
8:vId:=@vBomCalculationComponentsMultipleId;<br />
9:vId:=@vBomCalculationFooterMultipleId;<br />
10:vId:=@vImportVariantsId;<br />
11:vId:=@vImportToTablesId;<br />
12:vId:=@vImportToFieldsId;<br />
13:vId:=@vImportFromTablesId;<br />
14:vId:=@vImportFromFieldsId;<br />
end;<br />
try<br />
//Find last value of Id and save it to global variable<br />
Last;<br />
vCurrentId:=FieldByName(Name+'Id').AsInteger;<br />
if (vCurrentId>vId^) then vId^:=vCurrentId;<br />
finally<br />
//Remove reference;<br />
vId:=nil;<br />
end;<br />
end;<br />
end;<br />
finally<br />
vSuppressEvents:=False;<br />
//Refresh all datasets and enable controls<br />
for I:=Low(vSaveTables) to High(vSaveTables) do begin<br />
vSaveTables[I].Refresh;<br />
vSaveTables[I].EnableControls;<br />
end;<br />
MemoMessages.Lines.Append(TimeToStr(Now())+' Autoincrement fields - done.');<br />
end;<br />
end;</syntaxhighlight><br />
<br />
<syntaxhighlight lang=pascal><br />
function StringToCaseSelect(Selector:string;CaseList:array of string):Integer;<br />
var <br />
cnt: integer;<br />
begin<br />
Result:=-1;<br />
for cnt:=0 to Length(CaseList)-1 do<br />
begin<br />
if CompareText(Selector, CaseList[cnt]) = 0 then<br />
begin<br />
Result:=cnt;<br />
Break;<br />
end;<br />
end;<br />
end;</syntaxhighlight><br />
<br />
The GetAutoincrementPrimaryFields procedure is called every time after you restore (load) data from persistent files, in order to load last autoincrement values into global variables (or properties, as you prefer).<br />
Autoincrementing is done in OnNewRecord event of every MemDataset. For example, for MemDataset Orders:<br />
<br />
<syntaxhighlight lang=pascal><br />
procedure TMainForm.OrdersNewRecord(DataSet: TDataSet);<br />
begin<br />
if vSuppressEvents=True then Exit;<br />
//Set new autoincrement value<br />
vOrdersId:=vOrdersId+1;<br />
DataSet.FieldByName('OrdersId').AsInteger:=vOrdersId;<br />
end;</syntaxhighlight><br />
<br />
As already explained, I use vSuppressEvents global variable as flag for the case of restoring data from persistent files.<br />
<br />
== Enforcing Referential Integrity ==<br />
There is no enforced referential integrity implemented in MemDataset component, so you have to do it on your own.<br />
<br />
Let's assume we have two tables: MasterTable and DetailTable.<br />
<br />
There are various places where referential integrity code needs to be used:<br />
* Insert/Update code is located in the <code>BeforePost</code> event of the DetailTable: before a new/updated detail record is posted/saved, it needs to be checked for meeting referential integrity requirements<br />
* Delete code is located in the <code>BeforeDelete</code> event of the MasterTable: before a master record is deleted, it needs to make sure any child records meet referential integrity requirements<br />
<br />
<syntaxhighlight lang=pascal><br />
procedure TMainForm.MasterTableBeforeDelete(DataSet: TDataSet);<br />
begin<br />
if vSuppressEvents=True then Exit;<br />
try<br />
DetailTable.DisableControls;<br />
// Enforce referential delete ("cascade delete") for table "MasterTable"<br />
while not DetailTable.EOF do begin<br />
DetailTable.Delete;<br />
end;<br />
DetailTable.Refresh;<br />
finally<br />
DetailTable.EnableControls;<br />
end;<br />
end;<br />
</syntaxhighlight><br />
<br />
<syntaxhighlight lang=pascal><br />
procedure TMainForm.DetailTableBeforePost(DataSet: TDataSet);<br />
begin<br />
if vSuppressEvents=True then Exit;<br />
// Enforce referential insert/update for table "DetailTable" with<br />
// foreign key "MasterTableID" linking to<br />
// the MasterTable ID primary key field<br />
DataSet.FieldByName('MasterTableId').AsInteger:=<br />
MasterTable.FieldByName('ID').AsInteger;<br />
end;<br />
</syntaxhighlight><br />
<br />
After you provided referential Insert/Update/Delete, all you must do is provide code for master/detail filtering of data. You do it in the <code>AfterScroll</code> event of the MasterTable and in the <code>OnFilter</code> event of the DetailTable.<br />
<br />
Don't forget to set the <code>Filtered</code> property of DetailTable to True.<br />
<br />
<syntaxhighlight lang=pascal><br />
procedure TMainForm.MasterTableAfterScroll(DataSet: TDataSet);<br />
begin<br />
if vSuppressEvents=True then Exit;<br />
DetailTable.Refresh;<br />
end;<br />
</syntaxhighlight><br />
<br />
<syntaxhighlight lang=pascal><br />
procedure TMainForm.DetailTableFilterRecord(DataSet: TDataSet;<br />
var Accept: Boolean);<br />
begin<br />
if vSuppressEvents=True then Exit;<br />
// Show only child fields whose foreign key points to current<br />
// master table record<br />
Accept:=DataSet.FieldByName('MasterTableId').AsInteger=<br />
MasterTable.FieldByName('ID').AsInteger;<br />
end;<br />
</syntaxhighlight><br />
<br />
== Known problems ==<br />
There are several limitations when using MemDatasets.<br />
*Locate method does not work<br />
*Filtering by using Filter and Filtered property does not work. You must use hardcoding in the OnFilter event.<br />
*Looping deletion of records seems to be incredibly slow. Therefore I use my EmptyMemDataset procedure instead of while not EOF do Delete;<br />
* In FPC 2.6.x and earlier, CopyFromDataSet method copies data only from the current cursor position to the end of the source dataset. So, you have to write MemDataset1.First; before MemDataSet2.CopyFromDataSet(MemDataset1);. Fixed in FPC trunk revision 26233.<br />
** Note that older versions of FPC has no CopyFromDataset in Bufdataset, at the time an advantage for MemDs.<br />
** See bug report http://bugs.freepascal.org/view.php?id=25426.<br />
<br />
== TBufDataSet ==<br />
As previously mentioned, MemDataSet lacks custom filters, autoincrement data type and the Locate method, so it is better to use TBufDataSet instead.<br />
TBufDataset is provided by the BufDataset unit.<br />
<br />
Since there is no component for design-time editing of TBufDataSet (but you can set up field definitions at design time), you could create a custom wrapper component or use it through code, in the same way as ClientDataSet in Delphi. Look at the Delphi documentation relating to client datasets for details. <br />
<br />
You can use the same methods for enforcing referential integrity and primary autoincrement fields as explained for MemDataSet. <br />
<br />
There are only small differences between MemDataSet and BufDataset:<br />
{| class="wikitable sortable"<br />
! MemDataSet<br />
! BufDataset<br />
|----<br />
|DataSet.ClearFields||DataSet.Fields.Clear<br />
|----<br />
|DataSet.CreateTable||DataSet.CreateDataSet<br />
|}<br />
<br />
== Sorting DBGrid on TitleClick event for TBufDataSet ==<br />
If you wish to enable consecutive ascending and descending sorting of a DBGrid showing some data from TBufDataSet, you could use the following method:<br />
<br />
<syntaxhighlight lang=pascal><br />
Uses<br />
BufDataset, typinfo;<br />
<br />
function SortBufDataSet(DataSet: TBufDataSet;const FieldName: String): Boolean;<br />
var<br />
i: Integer;<br />
IndexDefs: TIndexDefs;<br />
IndexName: String;<br />
IndexOptions: TIndexOptions;<br />
Field: TField;<br />
begin<br />
Result := False;<br />
Field := DataSet.Fields.FindField(FieldName);<br />
//If invalid field name, exit.<br />
if Field = nil then Exit;<br />
//if invalid field type, exit.<br />
if {(Field is TObjectField) or} (Field is TBlobField) or<br />
{(Field is TAggregateField) or} (Field is TVariantField)<br />
or (Field is TBinaryField) then Exit;<br />
//Get IndexDefs and IndexName using RTTI<br />
if IsPublishedProp(DataSet, 'IndexDefs') then<br />
IndexDefs := GetObjectProp(DataSet, 'IndexDefs') as TIndexDefs<br />
else<br />
Exit;<br />
if IsPublishedProp(DataSet, 'IndexName') then<br />
IndexName := GetStrProp(DataSet, 'IndexName')<br />
else<br />
Exit;<br />
//Ensure IndexDefs is up-to-date<br />
IndexDefs.Updated:=false; {<<<<---This line is critical as IndexDefs.Update will do nothing on the next sort if it's already true}<br />
IndexDefs.Update;<br />
//If an ascending index is already in use,<br />
//switch to a descending index<br />
if IndexName = FieldName + '__IdxA'<br />
then<br />
begin<br />
IndexName := FieldName + '__IdxD';<br />
IndexOptions := [ixDescending];<br />
end<br />
else<br />
begin<br />
IndexName := FieldName + '__IdxA';<br />
IndexOptions := [];<br />
end;<br />
//Look for existing index<br />
for i := 0 to Pred(IndexDefs.Count) do<br />
begin<br />
if IndexDefs[i].Name = IndexName then<br />
begin<br />
Result := True;<br />
Break<br />
end; //if<br />
end; // for<br />
//If existing index not found, create one<br />
if not Result then<br />
begin<br />
if IndexName=FieldName + '__IdxD' then<br />
DataSet.AddIndex(IndexName, FieldName, IndexOptions, FieldName)<br />
else<br />
DataSet.AddIndex(IndexName, FieldName, IndexOptions);<br />
Result := True;<br />
end; // if not<br />
//Set the index<br />
SetStrProp(DataSet, 'IndexName', IndexName);<br />
end;</syntaxhighlight><br />
<br />
So, you can call this function from a DBGrid in this way:<br />
<br />
<syntaxhighlight lang=pascal><br />
procedure TFormMain.DBGridProductsTitleClick(Column: TColumn);<br />
begin<br />
SortBufDataSet(Products, Column.FieldName);<br />
end;</syntaxhighlight><br />
<br />
<br />
== Sorting multiple columns in grid ==<br />
I have written TDBGridHelper for sorting grid by multiple columns while holding shift key. <br />
Note MaxIndexesCount must be set quite large for TBufDataSet because there can be quite large combinations of possible sorting options. But I think people would not use more than 10 so setting it 100 should be teoretically Ok.<br />
<br />
<syntaxhighlight lang=pascal><br />
{ TDBGridHelper }<br />
<br />
TDBGridHelper = class helper for TDBGrid<br />
public const<br />
cMaxColCOunt = 3;<br />
private<br />
procedure Interbal_MakeNames(Fields: TStrings; out FieldsList, DescFields: String);<br />
procedure Internal_SetColumnsIcons(Fields: TStrings; AscIdx, DescIdx: Integer);<br />
function Internal_IndexNameExists(IndexDefs: TIndexDefs; IndexName: String): Boolean;<br />
public<br />
procedure Sort(const FieldName: String; AscIdx: Integer = -1; DescIdx: Integer = -1);<br />
procedure ClearSort;<br />
end; <br />
<br />
{ TDBGridHelper }<br />
<br />
procedure TDBGridHelper.Interbal_MakeNames(Fields: TStrings; out FieldsList, DescFields: String);<br />
var<br />
FldList: TStringList;<br />
DscList: TStringList;<br />
FldDesc, FldName: String;<br />
i: Integer;<br />
begin<br />
if Fields.Count = 0 then<br />
begin<br />
FieldsList := '';<br />
DescFields := '';<br />
Exit;<br />
end;<br />
<br />
FldList := TStringList.Create;<br />
DscList := TStringList.Create;<br />
try<br />
FldList.Delimiter := ';';<br />
DscList.Delimiter := ';';<br />
<br />
for i := 0 to Fields.Count - 1 do<br />
begin<br />
Fields.GetNameValue(i, FldName, FldDesc);<br />
FldList.Add(FldName);<br />
<br />
if FldDesc = 'D' then<br />
DscList.Add(FldName);<br />
end;<br />
<br />
FieldsList := FldList.DelimitedText;<br />
DescFields := DscList.DelimitedText;<br />
finally<br />
FldList.Free;<br />
DscList.Free;<br />
end;<br />
end;<br />
<br />
procedure TDBGridHelper.Internal_SetColumnsIcons(Fields: TStrings; AscIdx, DescIdx: Integer);<br />
var<br />
i: Integer;<br />
FldDesc: String;<br />
begin<br />
for i := 0 to Self.Columns.Count - 1 do<br />
begin<br />
FldDesc := Fields.Values[Self.Columns[i].Field.FieldName];<br />
<br />
if FldDesc = 'A' then<br />
Self.Columns[i].Title.ImageIndex := AscIdx<br />
else<br />
if FldDesc = 'D' then<br />
Self.Columns[i].Title.ImageIndex := DescIdx<br />
else<br />
Self.Columns[i].Title.ImageIndex := -1<br />
end;<br />
end;<br />
<br />
function TDBGridHelper.Internal_IndexNameExists(IndexDefs: TIndexDefs; IndexName: String): Boolean;<br />
var<br />
i: Integer;<br />
begin<br />
for i := 0 to IndexDefs.Count - 1 do<br />
begin<br />
if IndexDefs[i].Name = IndexName then<br />
Exit(True)<br />
end;<br />
<br />
Result := False<br />
end;<br />
<br />
procedure TDBGridHelper.Sort(const FieldName: String; AscIdx: Integer;<br />
DescIdx: Integer);<br />
var<br />
Field: TField;<br />
DataSet: TBufDataset;<br />
IndexDefs: TIndexDefs;<br />
IndexName, Dir, DescFields, FieldsList: String;<br />
Fields: TStringList;<br />
begin<br />
if not Assigned(DataSource.DataSet) or<br />
not DataSource.DataSet.Active or<br />
not (DataSource.DataSet is TBufDataset) then<br />
Exit;<br />
DataSet := DataSource.DataSet as TBufDataset;<br />
<br />
Field := DataSet.FieldByName(FieldName);<br />
if (Field is TBlobField) or (Field is TVariantField) or (Field is TBinaryField) then<br />
Exit;<br />
<br />
IndexDefs := DataSet.IndexDefs;<br />
IndexName := DataSet.IndexName;<br />
<br />
if not IndexDefs.Updated then<br />
IndexDefs.Update;<br />
<br />
Fields := TStringList.Create;<br />
try<br />
Fields.DelimitedText := IndexName;<br />
Dir := Fields.Values[FieldName];<br />
<br />
if Dir = 'A' then<br />
Dir := 'D'<br />
else<br />
if Dir = 'D' then<br />
Dir := 'A'<br />
else<br />
Dir := 'A';<br />
<br />
//If shift is presed then add field to field list<br />
if ssShift in GetKeyShiftState then<br />
begin<br />
Fields.Values[FieldName] := Dir;<br />
//We do not add to sor any more field if total field count exids cMaxColCOunt<br />
if Fields.Count > cMaxColCOunt then<br />
Exit;<br />
end<br />
else<br />
begin<br />
Fields.Clear;<br />
Fields.Values[FieldName] := Dir;<br />
end;<br />
<br />
IndexName := Fields.DelimitedText;<br />
if not Internal_IndexNameExists(IndexDefs, IndexName) then<br />
begin<br />
Interbal_MakeNames(Fields, FieldsList, DescFields);<br />
TBufDataset(DataSet).AddIndex(IndexName, FieldsList, [], DescFields, '');<br />
end;<br />
<br />
DataSet.IndexName := IndexName;<br />
Internal_SetColumnsIcons(Fields, AscIdx, DescIdx)<br />
finally<br />
Fields.Free;<br />
end;<br />
end;<br />
<br />
procedure TDBGridHelper.ClearSort;<br />
var<br />
DataSet: TBufDataset;<br />
Fields: TStringList;<br />
begin<br />
if not Assigned(DataSource.DataSet) or<br />
not DataSource.DataSet.Active or<br />
not (DataSource.DataSet is TBufDataset) then<br />
Exit;<br />
DataSet := DataSource.DataSet as TBufDataset;<br />
<br />
DataSet.IndexName := '';<br />
<br />
Fields := TStringList.Create;<br />
try<br />
Internal_SetColumnsIcons(Fields, -1, -1)<br />
finally<br />
Fields.Free<br />
end<br />
end; <br />
</syntaxhighlight><br />
<br />
To use sorting you need to call helper methods in OnCellClick and onTitleClick.<br />
OnTitleClick - If you hold shift ads new column to sot list ore changes direction to selected column or just sorts one column<br />
OnCellClick - If you double click on cell[0, 0] grid clears its sorting<br />
<br />
<syntaxhighlight lang=pascal><br />
procedure TForm1.grdCountriesCellClick(Column: TColumn);<br />
begin<br />
if not Assigned(Column) then<br />
grdCountries.ClearSort<br />
end;<br />
<br />
procedure TForm1.grdCountriesTitleClick(Column: TColumn);<br />
begin<br />
grdCountries.Sort(Column.Field.FieldName, 0, 1);<br />
end; <br />
</syntaxhighlight><br />
<br />
If you have assigned TitleImageList then you can specify which image use for ascending and which for descending operations.<br />
<br />
== ZMSQL==<br />
<br />
Another, often better way to write in-memory databases is to use the [[ZMSQL| ZMSQL package]]:<br />
<br />
* [http://sourceforge.net/projects/lazarus-ccr/files/zmsql/ http://sourceforge.net/projects/lazarus-ccr/files/zmsql/]<br />
* [http://www.lazarus.freepascal.org/index.php/topic,13821.30.html http://www.lazarus.freepascal.org/index.php/topic,13821.30.html]<br />
* [http://lazarus.freepascal.org/index.php/topic,13821 http://lazarus.freepascal.org/index.php/topic,13821]<br />
<br />
== Contributors ==<br />
<br />
Original text written by: Zlatko Matić (matalab@gmail.com)<br />
<br />
Other contributions by contributors as shown in the page History.</div>Aribenhttps://wiki.freepascal.org/TSQLConnector/jaTSQLConnector/ja2024-03-26T22:02:54Z<p>Ariben: </p>
<hr />
<div>{{TSQLConnector}}<br />
{{Infobox databases/ja}}<br />
'''TSQLConnector''' [[image:tsqlconnector.png]] is a versatile database connector component for use with any supported database. The component is found on [[SQLdb tab]] of the [[Component Palette]].<br />
<br />
To configure database access, most important properties are:<br />
* ConnectorType:<br />
::{|<br />
|-<br />
| [[TIBConnection]] || <tt>Firebird</tt> <br />
|-<br />
| [[TMSSQLConnection]] || <tt>MSSQLServer</tt> <br />
|-<br />
| [[TMySQL40Connection]] || <tt>MySQL 4.0</tt><br />
|-<br />
| [[TMySQL41Connection]] || <tt>MySQL 4.1</tt><br />
|-<br />
| [[TMySQL50Connection]] || <tt>MySQL 5.0</tt> <br />
|-<br />
| [[TMySQL51Connection]] || <tt>MySQL 5.1</tt> <br />
|-<br />
| [[TMySQL55Connection]] || <tt>MySQL 5.5</tt> <br />
|-<br />
| [[TMySQL56Connection]] || <tt>MySQL 5.6</tt> <br />
|-<br />
| [[TMySQL57Connection]] || <tt>MySQL 5.7</tt> <br />
|-<br />
| [[TMySQL80Connection]] || <tt>MySQL 8.0</tt> <br />
|-<br />
| [[TODBCConnection]] || <tt>ODBC</tt> <br />
|-<br />
| [[TOracleConnection]] || <tt>Oracle</tt> <br />
|-<br />
| [[TPQConnection]] || <tt>Postgres</tt> <br />
|-<br />
| [[TSQLite3Connection]] || <tt>SQLite3</tt> <br />
|-<br />
| [[TSybaseConnection]] || <tt>Sybase</tt> <br />
|}<br />
* DatabaseName<br />
* Hostname<br />
* Password<br />
* [[TSQLTransaction|Transaction]]<br />
<br />
For any connector to function, it should be able to load the right drivers. *.dll style drivers are found if they are located in the same directory as the corresponding *.exe file.<br />
<br />
==See also==<br />
* [http://www.freepascal.org/docs-html/fcl/sqldb/tsqlconnector.html TSQLConnector doc]<br />
* [http://www.freepascal.org/docs-html/fcl/sqldb/universalconnectors.html Using universal database connectors]<br />
<br />
{{LCL Components}}</div>Aribenhttps://wiki.freepascal.org/ODBCConn/jaODBCConn/ja2024-03-26T14:19:02Z<p>Ariben: /* Examples */</p>
<hr />
<div>{{ODBCConn}}<br />
<br />
{{Infobox databases/ja}}<br />
The '''ODBCConn''' unit implements an SQLdb connection to Open Database Connectivity (ODBC) data sources. <br />
<br />
== Overview ==<br />
<br />
=== ODBC ===<br />
ODBC (Open Database Connectivity) is a technology that allows one to connect to a whole variety of databases using a single API, the ODBC API.<br />
<br />
There are ODBC implementations for various platforms and there are drivers for most Database Management Systems.<br />
Official ODBC documentation can be found at the [http://msdn.microsoft.com/en-us/library/ms710252(VS.85).aspx MSDN ODBC site].<br />
<br />
=== TODBCConnection ===<br />
FreePascal ships with ODBC headers; they are in the <code>odbcsql</code> and <code>odbcsqldyn</code> units.<br />
<code>[[TODBCConnection]]</code> is an <code>[[TSQLConnection]]</code> descendant providing a nice OOP wrapper for ODBC using the SQLdb framework.<br />
<br />
In Lazarus, you can find the <code>TODBCConnection</code> component on the SQLdb component tab.<br />
You can also use the <code>TODBCConnection</code> component in your code by adding <code>ODBCConn</code> to your uses clause.<br />
<br />
[[Image:sqldbcomponents.png]]<br />
<br />
What has been implemented:<br />
* executing queries and retrieving result sets<br />
* most field types, including blobs<br />
* query parameters (string and integer types)<br />
* preparing queries<br />
* UpdateIndexDefs (so you can use ApplyUpdates)<br />
<br />
What is left to be implemented:<br />
* proper transaction support; currently each connection corresponds to one transaction<br />
* some field types<br />
** SQL_TYPE_UTC* (these are mentioned in the ODBC docs, but seem not to be used in implementations)<br />
** SQL_INTERVAL_* (what would be the corresponding TFieldType?)<br />
** SQL_GUID (TGUIDField was not implemented, until recently)<br />
<br />
=== なぜ ODBC なのか ? ===<br />
FreePascal ships with components for connecting to several databases, such as MySQL, PostGreSQL, Firebird, Microsoft SQL Server (since 2.6.1), Oracle, etc.<br />
<br />
For those databases missing from the list, like [[MS Access|MS Access]] and perhaps Microsoft SQL Server, ODBC is an acceptable and well established solution.<br />
(VB.net/C# developers are recommended to use SQLClient rather than OLEDB or ODBC for the ultimate in performance, but here in Lazarus ODBC will work adequately and reliably)<br />
<br />
The TODBCConnection component was developed originally to circumvent the strict MySQL license for applications that are not GPLed or do not obey MySQL AB's [http://www.mysql.com/company/legal/licensing/foss-exception.html FLOSS exception].<br />
<br />
== ODBC と ODBC ドライバをインストールする ==<br />
<br />
Before you can connect to your database using ODBC, you need to install<br />
* an ODBC Driver Manager<br />
* an ODBC driver specific to the DBMS you want to connect to<br />
<br />
This section will give a brief overview of the steps involved. However, please consult the relevant documentation for a definitive reference.<br />
<br />
=== ODBC ドライバマネージャ ===<br />
<br />
==== Windows ====<br />
Windows has an ODBC Driver Manager built in, which allows DSNs to be set up, and other configuration. It is found in the ''Control Panel'', in later Windows versions with categorised sections it was moved into the ''Administrative Tools'' area. Or you may simply click the Start button and enter ''ODBC'' into the Run box (in Windows 7 this appears as "''Search programs and files''").<br />
<br />
You can, of course, create a desktop shortcut to the ODBC dialog if you find yourself using it frequently.<br />
<br />
[[Image:WinXPODBCDataSourceAdministratorDrivers.png]]<br />
<br />
==== Unices ====<br />
<br />
Two popular ODBC Driver Managers for Unix-based platforms are [http://www.unixodbc.org unixODBC] and [http://www.iodbc.org iODBC].<br />
<code>ODBCConn</code> is known to work with unixODBC; iODBC compatibility still has to be tested.<br />
<br />
===== Debian =====<br />
<br />
For Debian, you can install the ''unixodbc'' package:<br />
<br />
<syntaxhighlight lang="bash"><br />
aptitude install unixodbc<br />
aptitude install unixodbc-bin # if you want some GUI tools<br />
</syntaxhighlight><br />
<br />
The <code>odbcsqldyn</code> unit, and hence <code>odbcconn</code>, will search for a file called <code>libodbc.so</code>.<br />
It will ''not'' accept a file named like <code>libodbc.so.1</code> or <code>libodbc.so.1.0.0</code>.<br />
Debian's ''unixodbc'' package does not create a symlink with the name <code>/usr/lib/libodbc.so</code>; you must either<br />
* create the link yourself: <code>ln -s libodbc.so.1 /usr/lib/libodbc.so</code>, or<br />
* install the ''unixodbc-dev'' package, which does create the symlink.<br />
<br />
If you installed the ''unixodbc-bin'' package, you can run the <code>ODBCConfig</code> program to configure ODBC drivers and DSNs.<br />
<br />
[[Image:ODBCDataSourceAdministratorAbout.PNG]]<br />
<br />
===== Ubuntu =====<br />
<br />
For Ubuntu, follow the instruction for [[#Debian|Debian]].<br />
Note: the ''unixodbc-bin'' package might not be available from the default package repository.<br />
<br />
=== ODBC Drivers ===<br />
訳注:以下にリンクがありますが、保存の時にはじかれましたので、https://は省いてあります<br />
You can download latest ODBC drivers using the following links:<br />
<br />
www.devart.com/odbc/sqlserver/download.html Download SQL Server 32/64 bit ODBC driver - latest version of SQL Server ODBC driver which supports Windows, Mac OS X, Linux both on 32 and 64 versions. Compatible with SQL Server 2014\2012\2008 R2\ 2008\2005 (including Express edition), SQL Server 2000 (including MSDE), SQL Server 7, SQL Server Compact 4.0\3.5\3.1. Works on all Lazarus versions. <br />
<br />
www.devart.com/odbc/oracle/download.html Download Oracle 32/64 bit ODBC driver - latest version of Oracle ODBC driver which supports Windows, Mac OS X, Linux both on 32 and 64 versions. Compatible with Oracle servers: 12c, 11g, 10g, 9i, 8i, 8.0, including Oracle Express Edition 11g and 10g. <br />
Oracle Clients: 12c, 11g, 10g, 9i, 8i, 8.0. <br />
Works on all Lazarus versions.<br />
<br />
www.devart.com/odbc/mysql/download.html Download MySQL 32/64 bit ODBC driver - latest version of MySQL ODBC driver which supports Windows, Mac OS X, Linux both on 32 and 64 versions. Compatible with MySQL servers: 6.0, 5.6, 5.5, 5.1, 5.0, 4.1, 4.0, and 3.23. MariaDB 5.x <br />
Works on all Lazarus versions. <br />
<br />
www.devart.com/odbc/postgresql/download.html Download PostgreSQL 32/64 bit ODBC driver - latest version of PostgreSQL ODBC driver which supports Windows, Mac OS X, Linux both on 32 and 64 versions. Compatible with PostgreSQL server versions since 7.1 up to 9.4. Works on all Lazarus versions.<br />
<br />
www.devart.com/odbc/postgresql/download.html Download SQLite 32/64 bit ODBC driver - latest version of SQLite ODBC driver which supports Windows, Mac OS X, Linux both on 32 and 64 versions. Compatible with SQLite versions since 3.0 and higher. Works on all Lazarus versions.<br />
<br />
www.devart.com/odbc/firebird/download.html Download Firebird 32/64 bit ODBC driver - latest version of Firebird ODBC driver which supports Windows, Mac OS X, Linux both on 32 and 64 versions. Compatible with Firebird versions 3, 2.x, 1.x. Works on all Lazarus versions.<br />
<br />
www.devart.com/odbc/interbase/download.html Download Interbase 32/64 bit ODBC driver - latest version of Interbase ODBC driver which supports Windows, Mac OS X, Linux both on 32 and 64 versions. Compatible with all Interbase versions. Works on all Lazarus versions.<br />
<br />
www.devart.com/odbc/sqlazure/download.html Download SQL Azure 32/64 bit ODBC driver - latest version of SQL Azure ODBC driver which supports Windows, Mac OS X, Linux both on 32 and 64 versions. Compatible with all SQL Azure versions. Works on all Lazarus versions.<br />
<br />
== ODBC データソースに接続する ==<br />
<br />
The parameters for connecting to an ODBC data source are described in a ''connection string''.<br />
This is a string of the form <code>NAME=VALUE;NAME=VALUE</code>.<br />
<br />
<code>TODBCConnection</code> provides a wrapper around this connection string.<br />
Some of its properties are mapped to name-value pairs in the connection string, and custom parameters can be specified in the <code>Params</code> property (which is a <code>TStrings</code>).<br />
<br />
Before going to the details of this wrapper, you must first have a basic understanding of how an ODBC data source is identified.<br />
<br />
=== DSN 経由で ODBC 接続 ===<br />
<br />
An ODBC driver manager provides alternative ways to make DSN shortcuts for a set of parameters:<br />
* DSN ('''D'''ata'''S'''ource '''N'''ame): a system or user defined data source, identified by a (unique) name. DSNs can be configured using the ODBC Data Source Administrator or by manually editing the <code>odbc.ini</code> file (or registry).<br />
* File DSN: a file which contains connection parameters. An ODBC Data Source Administrator usually allows you to create File DSNs from the GUI.<br />
The parameters in a DSN or File DSN can always be combined with additional parameters in the connection string, for example to specify a password.<br />
<br />
By setting up a DSN the connection details can be verified to work within the manager dialog, and then the named DSN is all that is needed to use the connection later. The connection details are therefore ''decoupled'' from your application, as only the DSN name is used in your software - the DSN acting as a go-between.<br />
<br />
An advantage to using a named DSN is that you may easily switch between databases using the ODBC Manager, without changing your code. This is useful in commercial development to test for bugs using a number of sets of your clients' data.<br />
<br />
=== DSN なしで ===<br />
You may also connect via ODBC without using a DSN, simply supplying all the details in the Connection String that you would otherwise set up in a DSN (driver,server,database,login details). This more direct method avoids the need to set up a DSN when installing your application on a new machine.<br />
<br />
The ODBC specification defines a few parameters that can be used in a connection string:<br />
* Two special parameters, <code>DSN</code> and <code>FILEDSN</code>, allow one to select a set of pre-defined parameters, as described above.<br />
* The <code>DRIVER</code> specifies which ODBC driver to use. Obviously, this is a very important parameter.<br />
* The <code>UID</code> and <code>PWD</code> parameters are used to supply a username and password.<br />
All other parameters are driver dependent.<br />
Please refer to the documentation of the specific driver to learn more about available parameters and their names.<br />
<br />
=== TODBCConnection プロパティ ===<br />
<br />
The following table describes the mapping of <code>TODBCConnection </code> properties to ODBC connection string parameters:<br />
{| class="wikitable"<br />
! Property !! Type !! Connection string parameter<br />
|-<br />
| <code>Driver</code> || <code>string</code> || <code>DRIVER</code><br />
|-<br />
| <code>DatabaseName</code> || <code>string</code> || <code>DSN</code>, ''not'' to something like <code>DATABASENAME</code>, which is not part of the ODBC standard <br />
|-<br />
| <code>FileDSN</code> || <code>string</code> || <code>FILEDSN</code><br />
|-<br />
| <code>Password</code> || <code>string</code> || <code>PWD</code><br />
|-<br />
| <code>UserName</code> || <code>string</code> || <code>UID</code><br />
|-<br />
| <code>HostName</code> || <code>string</code> || ''none''; there is no corresponding parameter in the ODBC standard<br />
|-<br />
| <code>Params</code> || <code>TStrings</code> || Use this to specify custom parameters. Each item must be of the form <code>NAME=VALUE</code>.<br />
<br />
One important parameter that can be used is '''<code>AUTOCOMMIT</code>''' which determines if SQL statements are directly executed (without possibility of a rollback) (default setting, or set explicitly using <code>AUTOCOMMIT=1</code>) or whether you need to manually call StartTransaction and Commit, CommitRetaining or Rollback (set using <code>AUTOCOMMIT=0</code>)<br />
|}<br />
<br />
Note that <code>TODBCConnection</code> will take care of escaping parameter values in the connection string (when required).<br />
<br />
The <code>LoginPrompt</code> boolean property is not implemented yet.<br />
It would require finding the correct window handle, so a driver can show a GUI dialog to specify parameters.<br />
Note that this is not controlled by the connection string, but rather by the last parameter to the ODBC API function <code>SQLDriverConnect</code>.<br />
<br />
== 例 ==<br />
<br />
In this section, examples are given of connecting to certain DBMSs using their specific ODBC drivers.<br />
<br />
=== Excel に接続する ===<br />
Probably works on Windows only.<br />
<br />
To avoid errors like:<br />
<nowiki><br />
Could not start transaction! ODBC error details: LastReturnCode: SQL_ERROR; Record 1: SqlState: HYC00; NativeError: 106; Message: [Microsoft][ODBC Excel Driver]Optional feature not implemented ;<br />
</nowiki><br />
<br />
... you'll have to enable autocommit, something like <br />
<br />
<syntaxhighlight lang=pascal><br />
ODBCConnection1.Params.Add('AUTOCOMMIT=1');<br />
</syntaxhighlight><br />
<br />
=== MySQL に接続する===<br />
<br />
For a reference of supported parameters by the MyODBC driver, see [https://dev.mysql.com/doc/connector-odbc/en/connector-odbc-configuration-connection-parameters.html].<br />
<br />
Additionally you may check this www.devart.com/odbc/mysql/docs/using_odbc_driver.htm mysql odbc connection guide. It has a detail explanation of how to connect to MySQL using ODBC. <br />
<br />
The driver name differs a bit depending on the platform and MyODBC version; examples are :<br />
<br />
<syntaxhighlight lang=pascal><br />
{ properties of connection object, i.e. conn: TODBCConnection; }<br />
conn.Driver := 'MySQL'; // (Unix) <br />
conn.Driver := 'MySQL ODBC 3.51 Driver'; // (Windows)<br />
conn.Driver := 'MySQL Connector/ODBC v5'; // (Windows)<br />
// note: driver name doesn't need {} like it does in SQL Connection Strings elsewhere<br />
</syntaxhighlight><br />
<br />
Other parameters (when not using a DSN) :<br />
<br />
<syntaxhighlight lang=pascal><br />
conn.UserName := 'myUsername';<br />
conn.Password := 'myPassword';<br />
// conn.Params (TStrings) set using .add method :<br />
conn.Params.Add('server=example.com');<br />
conn.Params.Add('port=3306');<br />
conn.Params.Add('database=myDatabase');<br />
conn.Params.Add('charset=utf8');<br />
</syntaxhighlight><br />
<br />
=== MS Access に接続する===<br />
<br />
Please see [[MS Access]].<br />
<br />
=== Connecting to Microsoft SQL Server ===<br />
{{Note|Newer versions than FPC 2.6.0 and Lazarus versions using those support a direct SQLDB connection to MS SQL Server; see [[Lazarus_Database_Overview#Lazarus_and_MSSQL.2FSybase|MSSQL]] }}<br />
<br />
Use this www.devart.com/odbc/sqlserver/docs/using_odbc_driver.htm mssql odbc driver connection examples which include step by step tutorial and connection strings. <br />
<br />
See www.connectionstrings.com/sql-server#p7 for more details on connection strings.<br />
<br />
Microsoft SQL Server ODBC connection string example:<br />
<br />
<syntaxhighlight lang=pascal><br />
Server=<server name>; // or <server name>\<instance name><br />
Database=<database name>;<br />
</syntaxhighlight><br />
<br />
=== Oracle に接続する===<br />
<br />
Use this www.devart.com/odbc/oracle/docs/using_odbc_driver.htm odbc oracle connection guide to perform easy and painless connection to Oracle. <br />
<br />
Oracle ODBC connection string example:<br />
<br />
<syntaxhighlight lang=pascal><br />
Login Prompt=False;<br />
Data Source=ORCL;<br />
User ID=scott;<br />
Password=tiger<br />
</syntaxhighlight><br />
<br />
=== PosgreSQLに接続する ===<br />
<br />
Use this www.devart.com/odbc/postgresql/docs/using_odbc_driver.htm postgresql odbc connection guide to perform easy and painless connection to PostgreSQL database. <br />
<br />
PostgreSQL ODBC connection string example:<br />
<br />
<syntaxhighlight lang=pascal><br />
Login Prompt=False;<br />
Data Source=localhost;<br />
User ID=postgres;<br />
Password=postgres;<br />
Database=postgres;<br />
Schema=public<br />
</syntaxhighlight><br />
<br />
=== SQLite に接続する ===<br />
<br />
Use this www.devart.com/odbc/sqlite/docs/using_odbc_driver.htm sqlite odbc connection guide to perform easy and painless connection to SQLite database. <br />
<br />
SQLite ODBC connection string example:<br />
<br />
<syntaxhighlight lang=pascal><br />
Login Prompt=False;<br />
Database=c:\test.db3<br />
</syntaxhighlight><br />
<br />
=== Firebird に接続する ===<br />
<br />
Use this www.devart.com/odbc/firebird/docs/using_odbc_driver.htm firebird odbc connection guide to perform easy and painless connection to Firebird database. <br />
<br />
Firebird ODBC connection string example:<br />
<br />
<syntaxhighlight lang=pascal><br />
Data Source=127.0.0.1;<br />
User ID=sysdba;<br />
Password=masterkey;<br />
Client Library=fbclient.dll;<br />
Database=c:\fbd.fdb<br />
</syntaxhighlight><br />
<br />
==== Named DSN ====<br />
On Windows, you can use something like this with an existing named DSN:<br />
<br />
<syntaxhighlight lang=pascal><br />
{ properties of connection object, i.e. conn: TODBCConnection; }<br />
conn.DatabaseName := '<Your_DSN_Name>';<br />
{ Leave all other conn. properties empty }<br />
</syntaxhighlight><br />
<br />
==== DSN-less ====<br />
Without a DSN:<br />
<br />
<syntaxhighlight lang=pascal><br />
{ properties of connection object, i.e. conn: TODBCConnection; }<br />
conn.Driver := 'SQL Server';<br />
// note: driver name doesn't need {} like it does in SQL Connection Strings elsewhere<br />
{ Leave Hostname and DatabaseName properties empty }<br />
{ set conn.Params (TStrings) : }<br />
conn.Params.Add('Database=<yourdatabasename>');<br />
conn.Params.Add('Server=.\SQLEXPRESS');<br />
conn.Params.Add('Trusted_Connection=Yes'); // or 'Integrated Security=SSPI'<br />
</syntaxhighlight><br />
<br />
Note: In this example, we connect to the local machine (server=.), on the instance SQLEXPRESS. You can use a hostname instead of ., and you can omit the instance to connect to the default instance. See MS documentation for details.<br />
<br />
Using a trusted connection (also known as integrated security or SSPI) means you login using your Windows user credentials. You can omit the Trusted_Connection line, but then you need to specify user ID (Uid=...) and password (Pwd=...).<br />
<br />
==== DSN example ====<br />
The example code below selects the rows from a MS SQL Server table called 'journal_entries' and displays all the values of column 'journal_entry' in a Memo control called Memo1.<br />
<br />
<syntaxhighlight lang=pascal><br />
// uses ODBCConn, sqldb;<br />
procedure TForm1.Button1Click(Sender: TObject);<br />
var<br />
S: String;<br />
conn : TODBCConnection; // uses ODBCConn<br />
query: TSQLQuery; // uses sqldb<br />
transaction: TSQLTransaction; // uses sqldb<br />
<br />
begin<br />
conn := TODBCCOnnection.Create(nil);<br />
query := TSQLQuery.Create(nil);<br />
transaction := TSQLTransaction.Create(nil);<br />
try<br />
try<br />
conn.DatabaseName := 'sqlserverdsn'; {replace this with your DSN, if you use any}<br />
conn.UserName:= 'sa'; //replace with your user name<br />
conn.Password:= 'thepassword'; //replace with your password<br />
// You can override the properties defined in the DSN, e.g.<br />
//conn.Params.Add('Database=some_other_db');<br />
<br />
conn.Transaction := transaction;<br />
query.DataBase := conn;<br />
{ To avoid "could not retrieve primary key metadata":<br />
- either use query.UsePrimaryKeyAsKey:=false<br />
or (preferred)<br />
- query.PacketRecords to -1<br />
If you are using SQL Server, you could alternatively enable MARS in your SQL Native Client ODBC driver.<br />
See http://bugs.freepascal.org/view.php?id=13241 }<br />
query.PacketRecords:=-1; //retrieve all data at once<br />
query.SQL.Text := 'select journal_entry from journal_entries';<br />
query.Open;<br />
S := '';<br />
while not query.EOF do<br />
begin<br />
S := S + query.FieldByName('journal_entry').AsString + #13#10;<br />
query.Next;<br />
end;<br />
finally<br />
query.Free;<br />
conn.Free;<br />
transaction.Free;<br />
end;<br />
except<br />
on E: Exception do<br />
ShowMessage(E.message);<br />
end;<br />
Memo1.Text:= S;<br />
end;<br />
<br />
</syntaxhighlight><br />
<br />
In fact it is possible to use conn.Params for all parts of the connection string, if we modify the above - this time showing the SQL Server version in a pop-up message :<br />
<br />
<syntaxhighlight lang=pascal><br />
conn.Params.Add('Driver=SQL Server');<br />
conn.Params.Add('Server=OURBIGSERVER');<br />
conn.Params.Add('Database=TestDataBase');<br />
conn.Params.Add('Integrated Security=SSPI'); // use Windows logon credentials<br />
// no other conn. properties set, apart from conn.Transaction := transaction;<br />
<br />
query.DataBase := conn;<br />
query.SQL.Text := 'select @@version';<br />
query.Open;<br />
showmessage(query.Fields[0].AsString); // Fields are numbered starting from 0<br />
</syntaxhighlight><br />
<br />
Functions are supported - e.g. '<Code>SELECT * FROM MyTestFunc()</Code>' - but there may be issues with ''Stored Procedures'' that return recordsets. For example, if '<Code>EXEC MyStoredProcedure</Code>' returns data rows (verified in SQL Server Management Studio or with the ''SqlCmd'' DOS command: <Code>C:\>sqlcmd -S MyServer -E -d MyDataBase -Q "exec MySP"</Code>) then <Code>query.open</Code> will give an error : "Cannot open a non-select statement" (this may be fixed after FPC 2.6)<br />
<br />
To call a Stored Procedure or to issue other SQL commands that return no rowsets (CREATE,INSERT,UPDATE,DELETE), use <Code>query.ExecSQL</Code> instead of <Code>query.Open</Code><br />
<br />
Stored Procedure parameters work, e.g. '<Code>EXEC MySP @param1=23</Code>'<br />
<br />
The use of ''Parameters'' is recommended to avoid ''SQL injection vulnerabilities''. In this case the SQL statement isn't built with values directly, but a named placeholder is used instead - and then the parameter is specified separately. Using this method it isn't possible to inject malicious SQL commands into variable fields in an attempt to tamper with the database; the server then knows specifically what part of the statement is a value and what is command. For example, instead of building a WHERE clause directly with the value 95 (<Code>'... WHERE field2>95'</Code>), instead use a named parameter like 'testval' -<br />
<br />
<syntaxhighlight lang=pascal><br />
query.SQL.Text := 'select * from mytable where field2>:testval';<br />
query.Params.ParamByName('testval').AsString := '95';<br />
query.open; <br />
</syntaxhighlight><br />
<br />
== ODBCデバッグとエラー ==<br />
<br />
=== トランザクションの問題 ===<br />
In Lazarus 1.2.4 (FPC 2.6.4), ODBC transaction behaviour has changed.<br />
This may cause previously working code to stop working.<br />
<br />
For a solution, see [[User_Changes_2.6.4#TODBCConnection_.28odbcconn.29_No_longer_autocommit]]<br />
<br />
=== エラーメッセージ ===<br />
Each ODBC API call also returns a succes code; if there is an error, more information can be retrieved using calls to <code>SQLGetDiagRec</code>. (For the sake of completeness: diagnostic records are also available when an API call returns <code>SQL_SUCCES_WITH_INFO</code>.)<br />
<br />
<code>TODBCConnection</code> checks the return code of each ODBC call and contructs an <code>EODBCException</code>.<br />
The <code>message</code> of this exception consists of:<br />
* a message identifying what the <code>TODBCConnection</code> was doing when the error occurred<br />
* the return code of the ODBC API call (e.g. <code>SQL_ERROR</code>)<br />
* a number of diagnostic records (obtained using <code>SQLGetDiagRec</code>); each record consists of three fields:<br />
** a 5-character error code identifying the error<br />
** a 'native error code'<br />
** a message describing the error<br />
<br />
==== Function sequence error ====<br />
If you get a 'Function sequence error' in the finalization section of the <code>ODBCConn</code> unit, then you probably did not properly clean up all you queries and connections.<br />
<br />
==== Rollback が効かない ====<br />
If you issue <syntaxhighlight lang=pascal>TSQLTransaction.Rollback</syntaxhighlight> commands but your SQL is committed regardless, your ODBC connection probably is in AUTOCOMMIT mode; see [[ODBCConn#TODBCConnection_properties|the remarks about the AUTOCOMMIT connection parameter]] on how to correct this.<br />
<br />
=== 追跡 ===<br />
Most ODBC managers have a tracing option in which all ODBC API calls are logged to a trace log.<br />
This can be very useful for debugging an ODBC application.<br />
The ODBC Data Source Administration GUI of both Windows and unixODBC have a tab where you can configure the tracing option.<br />
<br />
Of course the trace log is mainly useful for developers that are familiar with the ODBC API, but it can help to identify the problem.<br />
Also, you can attach a trace log if you report a problem to the bug tracker.<br />
<br />
== 以下も参照のこと ==<br />
* [[MS Access]] Using ODBC to access Microsoft Access databases</div>Aribenhttps://wiki.freepascal.org/Oracle/jaOracle/ja2024-03-26T13:33:13Z<p>Ariben: </p>
<hr />
<div>{{Oracle}}<br />
<br />
{{Infobox databases/ja}}<br />
<br />
== 低階層 Oracle サーバインタフェース == <br />
The low level Oracle server interface exists of one unit, '''oraoci''', which is a straight translation of the Oracle interface header files. <br />
<br />
There are 2 example programs:<br />
<br />
* '''oraclew''' contains some utility routines for the oracle interface, for easier management of result sets. Needs the classes unit from the FCL.<br />
* '''test01''' a simple test program to demonstrate the interface. <br />
<br />
== Oracle へ直接接続==<br />
You can directly connect Lazarus and Oracle by using Oracle Data Access Components (ODAC). It is a library of components that provides native connectivity to Oracle from Lazarus (and Free Pascal) on Windows, Mac OS X, iOS, Android, Linux, and FreeBSD for both 32-bit and 64-bit platforms. The ODAC library is designed to help programmers develop faster and more native Oracle database applications.<br />
<br />
<!-- This [https://www.devart.com/odac/download.html Lazarus component] is free to download. --><br />
<br />
== Oracle へのOOPアクセス ==<br />
Built over the low-level interface, the SQLDB framework supplied with FPC supports accessing Oracle (using TOracleConnection); see also [[Lazarus_Database_Overview#Lazarus_and_Oracle]]<br />
<br />
Lazarus also has a component: [[TOracleConnection]]<br />
<br />
* Hostname: as with other sqldb connectors, use hostname or IP address. Leave empty if you use a TNSNAMES.ORA net service name in DatabaseName<br />
* Username/password: same as with other sqldb connectors<br />
* DatabaseName: <br />
** instance/SID of the Oracle server you want to connect to '''or'''<br />
** net service name in a TNSNAMES.ORA file<br />
<br />
{{Note|Released FPC/Lazarus x64 versions on Windows do not include an Oracle connector. If you enable it and test successfully, please submit a patch with the changes so it can be included}}<br />
<br />
== トラブルシューティング ==<br />
=== クライアントとサーバのキャラクタセット ===<br />
To get info about what character set/NLS settings are active, you can run the following program.<br />
<br />
Please don't forget to fill out correct server name, username, password and database name before compiling.<br />
<br />
<syntaxhighlight lang=pascal><br />
program oracharset;<br />
<br />
{ Shows client and server character set/NLS info}<br />
{ PLEASE EDIT PASSWORDS ETC BELOW. }<br />
<br />
{$mode objfpc}{$H+}<br />
<br />
uses {$IFDEF UNIX} {$IFDEF UseCThreads}<br />
cthreads, {$ENDIF} {$ENDIF}<br />
Classes,<br />
SysUtils,<br />
sqldb,<br />
oracleconnection;<br />
<br />
var<br />
Col: integer;<br />
Conn: TOracleConnection;<br />
Tran: TSQLTransaction;<br />
Q: TSQLQuery;<br />
begin<br />
Conn := TOracleConnection.Create(nil);<br />
Tran := TSQLTransaction.Create(nil);<br />
Q := TSQLQuery.Create(nil);<br />
try<br />
// * EDIT IDENTIFYING INFO AS NEEDED*<br />
Conn.HostName := '';<br />
Conn.UserName := 'system';<br />
Conn.Password := '';<br />
Conn.DatabaseName := 'XE';<br />
// *END IDENTIFIYING INFO*<br />
Conn.Transaction := Tran;<br />
Q.DataBase := Conn;<br />
Conn.Open;<br />
Tran.Active := true;<br />
<br />
writeln('Server character set info:');<br />
Q.SQL.Text := 'SELECT value$ FROM sys.props$ WHERE name like ''NLS_%'' ';<br />
Q.Open;<br />
Q.First;<br />
while not (Q.EOF) do<br />
begin<br />
writeln('*****************');<br />
for Col := 0 to Q.Fields.Count - 1 do<br />
begin<br />
try<br />
writeln(Q.Fields[Col].DisplayLabel + ':');<br />
writeln(Q.Fields[Col].AsString);<br />
except<br />
writeln('Error retrieving field ', Col);<br />
end;<br />
end;<br />
Q.Next;<br />
end;<br />
Q.Close;<br />
<br />
writeln('');<br />
writeln('Client character set info:');<br />
Q.SQL.Text := 'SELECT * FROM NLS_SESSION_PARAMETERS ';<br />
Q.Open;<br />
Q.First;<br />
while not (Q.EOF) do<br />
begin<br />
writeln('*****************');<br />
for Col := 0 to Q.Fields.Count - 1 do<br />
begin<br />
try<br />
writeln(Q.Fields[Col].DisplayLabel + ':');<br />
writeln(Q.Fields[Col].AsString);<br />
except<br />
writeln('Error retrieving field ', Col);<br />
end;<br />
end;<br />
Q.Next;<br />
end;<br />
Q.Close;<br />
// *END EXAMPLE BUG TESTING CODE*<br />
Conn.Close;<br />
finally<br />
Q.Free;<br />
Tran.Free;<br />
Conn.Free;<br />
end;<br />
writeln('Program complete. Press a key to continue.');<br />
readln;<br />
end.<br />
</syntaxhighlight><br />
<br />
=== ORA-00911 : invalid character ===<br />
If you see this error message, you might want to try<br />
* removing a trailing semicolon - ; - if you have it in a SELECT statement<br />
* adding a trailing semicolon (e.g. in CALL or EXECUTE statements)<br />
See this thread which applies to .Net but may apply to SQLDB as well: [http://social.msdn.microsoft.com/Forums/en/adodotnetdataproviders/thread/58a27505-a3fb-4cb1-9063-3946b3f26acd]<br />
<br />
Go back to [[Packages List]]</div>Aribenhttps://wiki.freepascal.org/Portal:Databases/ja/Development_TechniquesPortal:Databases/ja/Development Techniques2024-03-25T15:46:42Z<p>Ariben: Created page with "{| |- valign="top" | * Database introduction * Lazarus Database Overview * SqlDBHowto * Working With TSQLQuery/ja * SQLdb Tutorial0/ja * SQ..."</p>
<hr />
<div>{| <br />
|- valign="top"<br />
|<br />
* [[Databases/ja|Database introduction]]<br />
* [[Lazarus Database Overview]]<br />
* [[SqlDBHowto]]<br />
* [[Working With TSQLQuery/ja]]<br />
* [[SQLdb Tutorial0/ja]]<br />
* [[SQLdb Tutorial1/ja]]<br />
* [[SQLdb Tutorial2/ja]]<br />
* [[SQLdb Tutorial3]]<br />
* [[SQLdb Tutorial4]]<br />
|<br />
* [[TSQLConnector]]<br />
* [[TSQLTransaction]]<br />
* [[TSQLQuery]]<br />
* [[TDataSet]]<br />
* [[TDBNavigator]]<br />
* [[TDBGrid]]<br />
* [[TDBEdit]]<br />
* [[TDBImage]]<br />
* [[SQLdb tab]]<br />
|<br />
* [[TSQLScript]]<br />
* [[TSQLExporter]]<br />
|<br />
*[[MasterDetail]]<br />
|}<noinclude><br />
'''Hint: This section is for inclusion in the [[Portal:Databases/ja]].'''<br><br />
(This hint is not included)<br />
</noinclude></div>Aribenhttps://wiki.freepascal.org/Portal:Databases/jaPortal:Databases/ja2024-03-25T14:56:53Z<p>Ariben: </p>
<hr />
<div>{{Index-Portal}}<br />
<br />
{{Portal_Head2|555555|<big>{{PAGENAME}}</big>|bbbbbb|000000}}<br />
{| width="100%" class = "wikitable"<br />
| valign="top" |<br />
[[File:laz database icon.png|right]]<br />
このポータルは、LazarusとFree Pascalでのデータベース接続の開発の概要を提供する。<br />
<br />
|- <br />
| valign="top" |<br />
<div style="margin-left:1em"><br />
<br />
{{Portal_Head2|555555|'''関連する話題'''}}<br />
'''Platform Portals:''' [[Portal:Android|Android]] - [[Portal:Embedded|Embedded]] - [[Portal:FreeBSD|FreeBSD]] - [[Portal:iOS|iOS]] - [[Portal:Linux|Linux]] - [[Portal:Mac|Mac]] - [[Portal:Windows|Windows]]<br />
<br />
'''ポータルの話題:''' [[Portal:New Users/ja|<font color=green>'''New Users'''</font>]] - [[Portal:Databases/ja|データベース開発]] - [[Portal:Game Development/ja|Game Development]] - [[Portal:Hardware and Robotics|Hardware and Robotics]] - [[Portal:HowTo Demos|HowTo Demos]] - [[Portal:SciTech|Science and Technology]] - [[Portal:Web_Development|Web Development]] <br />
<br />
'''Category:''' '''[[:Category:Databases|Databases]]'''<br />
</div><br />
|}<br />
<gallery> <br />
File:MetaDataEditor.png<br />
File:Laz SqlDB components.png<br />
File:dm2.jpg<br />
File:Screenshot-Master Detail Example - SQLLite3-2.png<br />
</gallery><br />
<div style="float:left; width:60%;"> <!-- Both "width" values should add up to 100% --><br />
<br />
{{Portal_Head|555555|開発テクニック|bbbbbb|000000||Template:Portal:Databases/Development Techniques/ja}}<br />
<!-- ------------------------ DEVELOPMENT TECHNIQUES ---------------------------- --><br />
{| width="100%" class = "wikitable"<br />
| valign="top" |<br />
{{Template:Portal:Databases/Development Techniques/ja}}<br />
|}<br />
<br/><br />
{{Portal_Head|555555|データベースマネジメントシステム|bbbbbb|000000||Template:Portal:Databases/DBMS/ja}}<br />
<!-- ------------------------ DBMS ---------------------------- --><br />
{| width="100%" class = "wikitable"<br />
| valign="top" |<br />
{{Template:Portal:Databases/DBMS/ja}}<br />
|}<br />
</div><br />
<div style="float:right; width:39%"> <!-- Both "width" values should add up to 100% --><br />
<br />
{{Portal_Head|555555|特別の話題|bbbbbb|000000||Template:Portal:Databases/Special Topics/ja}}<br />
<!-- ------------------------ SPECIAL TOPICS ---------------------------- --><br />
{| width="100%" class = "wikitable"<br />
| valign="top" |<br />
{{Template:Portal:Databases/Special Topics/ja}}<br />
|}<br />
<br/><br />
{{Portal_Head|555555|型、API、ヘッダ|bbbbbb|000000||Template:Portal:Databases/APIs and Headers/ja}}<br />
<!-- ------------------------ TYPES, APIS AND HEADERS ---------------------------- --><br />
{| width="100%" class = "wikitable"<br />
| valign="top" |<br />
{{Template:Portal:Databases/APIs and Headers/ja}}<br />
|}<br />
<br/><br />
{{Portal_Head|555555|FAQs|bbbbbb|000000||Template:Portal:Databases/FAQs/ja}}<br />
<!-- ------------------------ FAQs ---------------------------- --><br />
{| width="100%" class = "wikitable"<br />
| valign="top" |<br />
{{Template:Portal:Databases/FAQs/ja}}<br />
|}<br />
</div><br />
<br />
[[Category:Databases|!Database Portal/ja]]<br />
[[Category:Portals|Database Portal/ja]]</div>Aribenhttps://wiki.freepascal.org/TNotebook/jaTNotebook/ja2024-03-25T13:25:13Z<p>Ariben: Created page with "{{TNotebook}} image:tnotebook.png'''TNotebook'''は、さまざまなコントロールをページに配置して保持するコンテナを提供するコンポーネ..."</p>
<hr />
<div>{{TNotebook}}<br />
<br />
[[image:tnotebook.png]]'''TNotebook'''は、さまざまなコントロールをページに配置して保持するコンテナを提供するコンポーネントである。実際のノートブックのように、複数のページを持つことができる。TNotebookは[[TWinControl]]の派生であり、[[Component Palette/ja]]の[[Additional tab/ja]]タブで利用できる。<br />
<br />
== Navigating from page to page ==<br />
All pages of the <tt>TNotebook</tt> are listed by the <tt>Pages</tt> property, a <tt>TStrings</tt> class which contains the page names. There is also a property <tt>Page</tt> (note the singular!) which lists the <tt>TPage</tt> controls into which other controls can be inserted. <br />
<br />
Unlike [[TPageControl]] the <tt>TNotebook</tt> does not have tabs. Therefore, navigation between pages is not as easy as with <tt>TPageControl</tt>:<br />
<br />
* At designtime the pages are listed in the object tree of the Object Inspector under the Notebook node; here the developer can easily switch from page to page. <br />
* At runtime, special code must be provided to show a specific page; the <tt>PageIndex</tt> property determines which page is currently visible. Here is an example for application of <tt>TNotebook</tt> in a tabless, wizard-like form with "Forward"/"Backward" buttons to move from page to page:<br />
<syntaxhighlight lang=Pascal>procedure TForm1.ForwardBtnClick(Sender: TObject);<br />
begin<br />
if Notebook1.PageIndex < Notebook1.PageCount-1 then<br />
Notebook1.PageIndex := Notebook1.PageIndex + 1;<br />
end;<br />
<br />
procedure TForm1.BackwardBtnClick(Sender: TObject);<br />
begin<br />
if Notebook1.PageIndex > 0 then<br />
Notebook1.PageIndex := Notebook1.PageIndex - 1;<br />
end; <br />
</syntaxhighlight><br />
<br />
== Adding pages ==<br />
Pages can be added at designtime by right-clicking on the <tt>TNotebook</tt> component and selecting ''Add Page'' from the context menu. <br />
<br />
At runtime, a page is added by calling <tt>Notebook.Add('new pagename')</tt> with the name of the new page as parameter; the function returns the index of the new page. As already noted, the new page itself can be addressed by using the property <tt>Notebook.Page[newindex]</tt> (note the singular). The following example adds a new page and puts a <tt>TMemo</tt> on it:<br />
<syntaxhighlight lang=Pascal>procedure TForm1.NewPageBtnClick(Sender: TObject);<br />
var<br />
newIndex: Integer;<br />
begin<br />
newIndex := Notebook1.Pages.Add('New Page'); // use plural!<br />
with TMemo.Create(self) do<br />
begin<br />
Parent := Notebook1.Page[newIndex]; // use singular!<br />
Align := alClient;<br />
end;<br />
end; </syntaxhighlight><br />
<br />
== Removing pages ==<br />
At designtime, a page can be removed by using the context menu of the <tt>TNotebook</tt> and selecting the menu item ''Delete Page''.<br />
<br />
At runtime, a page is removed by deleting the corresponding index from the <tt>Pages</tt> list (plural!), or by destroying the <tt>Page[index]</tt> (singular!) at the specific index<br />
<br />
<syntaxhighlight lang=Pascal><br />
procedure TForm1.DeleteCurrPageBtn(Sender: TObject);<br />
begin<br />
if Notebook1.PageIndex > -1 then<br />
Notebook1.Pages.Delete(Notebook1.PageIndex);<br />
// or: Notebook1.Page[Notebook1.PageIndex].Free<br />
end;<br />
end;</syntaxhighlight><br />
<br />
== Similar controls ==<br />
* [[TPageControl]]<br />
* [[TTabControl]]<br />
<br />
==See also==<br />
* [[doc:lcl/extctrls/tnotebook.html|TNoteBook doc]]<br />
* [[doc:lcl/extctrls/multi-pagecontrols.html|Multi-page controls doc]]<br />
<br />
{{LCL Components/ja}}</div>Aribenhttps://wiki.freepascal.org/TPaintBox/jaTPaintBox/ja2024-03-25T13:16:44Z<p>Ariben: Created page with "{{TPaintBox}} '''TPaintBox'''image:tpaintbox.pngは、描画領域を提供するコンポーネントである。TPaintBoxはTGraphicControlの派生であり、Co..."</p>
<hr />
<div>{{TPaintBox}}<br />
<br />
'''TPaintBox'''[[image:tpaintbox.png]]は、描画領域を提供するコンポーネントである。TPaintBoxは[[TGraphicControl]]の派生であり、[[Component Palette/ja]]の[[Additional tab/ja]]タブで利用できる。<br />
<br />
TPaintBox上の描画は、そのCanvasプロパティを介して行われる。Canvasは[[TCanvas]]である。<br />
<br />
==以下も参照のこと==<br />
* [[doc:lcl/extctrls/tpaintbox.html|TPaintBox doc]]<br />
* [[TImage/ja]]<br />
<br />
{{LCL Components/ja}}</div>Aribenhttps://wiki.freepascal.org/TBevel/jaTBevel/ja2024-03-25T13:08:48Z<p>Ariben: /* 以下も参照のこと */</p>
<hr />
<div>{{TBevel}}<br />
<br />
'''TBevel'''[[image:tbevel.png]]は、フォーム上にベベルを作成するコンポーネントである。TBevelは[[TGraphicControl]]の派生であり、[[Component Palette/ja]]の[[Additional tab/ja]]タブで利用できる。<br />
<br />
ベベルは、3Dの四角形の錯覚を加える。ベベルの内部領域は下がっているように見えます(デフォルト)または上がっているように見える。<br />
<br />
==以下も参照のこと==<br />
* [[doc:lcl/extctrls/tbevel.html|TBevel doc]]<br />
* [[TShape/ja]]<br />
* [[TPanel/ja]]<br />
* [[TFrame/ja]]<br />
<br />
{{LCL Components/ja}}</div>Aribenhttps://wiki.freepascal.org/TShape/jaTShape/ja2024-03-25T13:00:28Z<p>Ariben: Created page with "{{TShape}} '''TShape''' image:tshape.pngは、親コンポーネント(たとえばTForm)の表面に形状(三角形、円、または四角形)を作成するコン..."</p>
<hr />
<div>{{TShape}}<br />
<br />
'''TShape''' [[image:tshape.png]]は、親コンポーネント(たとえば[[TForm]])の表面に形状(三角形、円、または四角形)を作成するコンポーネントです。これは[[TGraphicControl]]の派生であり、[[Component Palette/ja]]の[[Additional tab/ja]]タブで利用できます。<br />
<br />
==以下も参照のこと==<br />
* [[doc:lcl/extctrls/tshape.html|TShape doc]]<br />
* [[TArrow]]<br />
<br />
{{LCL Components/ja}}</div>Aribenhttps://wiki.freepascal.org/TStaticText/jaTStaticText/ja2024-03-25T12:41:09Z<p>Ariben: Created page with "{{TStaticText}} '''TStaticText''' image:tstatictext.pngは、別のコンポーネント上にテキスト項目を作成するコンポーネントである。TStaticTex..."</p>
<hr />
<div>{{TStaticText}}<br />
<br />
'''TStaticText''' [[image:tstatictext.png]]は、別のコンポーネント上にテキスト項目を作成するコンポーネントである。TStaticTextは[[TWinControl]]の派生であり、[[Component Palette/ja]]の[[Additional tab/ja]]タブで利用できる。デフォルトで[[Transparent]]プロパティをサポートするLCLコンポーネントのうちの1つである。<br />
<br />
==以下も参照のこと==<br />
<br />
* [[TLabel]]<br />
* [[doc:/lcl/stdctrls/tstatictext.html|TStaticText doc]]<br />
<br />
{{LCL Components/ja}}</div>Aribenhttps://wiki.freepascal.org/TSpeedButton/jaTSpeedButton/ja2024-03-25T12:31:23Z<p>Ariben: Created page with "{{TSpeedButton/ja}} '''TSpeedButton'''image:tspeedbutton.pngは、その表面に描画されたビットマップを持つ(小さい)ボタンを作成するコンポー..."</p>
<hr />
<div>{{TSpeedButton/ja}}<br />
<br />
'''TSpeedButton'''[[image:tspeedbutton.png]]は、その表面に描画されたビットマップを持つ(小さい)ボタンを作成するコンポーネントである。これは[[TGraphicControl]]の派生であり、[[Component Palette/ja]]の[[Additional tab/ja]]で利用できる。<br />
<br />
==以下も参照のこと==<br />
* [[doc:lcl/buttons/tspeedbutton.html|TSpeedButton doc]]<br />
* [[TButton/ja]]<br />
* [[TBitBtn/ja]]<br />
* [[TColorButton]]<br />
<br />
{{LCL Components/ja}}</div>Aribenhttps://wiki.freepascal.org/TBitBtn/jaTBitBtn/ja2024-03-24T14:40:56Z<p>Ariben: </p>
<hr />
<div>{{TBitBtn}}<br />
<br />
'''TBitBtn''' [[image:tbitbtn.png]]は、その表面に描画されたビットマップを持つボタンを作成するコンポーネントである。TBitBtnはTWinControlの派生であり、[[Component Palette/ja]]の[[Additional tab/ja]]タブの下で利用できる。<br />
<br />
標準のボタンを使用しやすくするために、TBitBtnには''Kind''というプロパティがある。このプロパティを使用すると、''bkOk''のようなボタンの種類を選択できる。これにより、テキストと対応する画像を持つ[OK]ボタンを作成できる(''Glyp''、モーダル結果 ''mrOk'')。<br />
<br />
[[image:component-TBitBtn.png]]<br />
<br />
GlyphとCaptionの配置は、これらのプロパティを使用して制御できる:<br />
* <code>Layout</code>は、<code>blGlyphLeft</code>、<code>blGlyphRight</code>、<code>blGlyphTop</code>、および<code>blGlyphBottom</code>の列挙型である。これは、それぞれのキャプションの左側、右側、上側、または下側にグリフが配置されるかどうかを決定する。デフォルトは<code>blGlyphLeft</code>である。<br />
* <code>Margin</code>は、ボタンの端とグリフの間の距離(ピクセル単位)である。値が-1の場合、グリフとキャプションの組み合わせがボタン内で中央揃えになる。デフォルト値は<code>-1</code>である。<br />
* <code>Spacing</code>は、グリフとキャプションの間の距離(ピクセル単位)を示す。値が-1の場合、キャプションはグリフとボタンの端との間で中央揃えされる。また、Marginが-1の場合、グリフとキャプションはボタンの領域内で均等に配置される。デフォルト値は<code>4</code>である。<br />
フォームに複数の縦に積み重ねられたBitBtnコンポーネント(<code>Layout=blGlyphLeft</code>)があり、グリフとキャプションを左揃えにしたい場合は、<code>Margin</code>と<code>Spacing</code>を4などの正の値に設定する。<br />
<br />
==以下も参照のこと==<br />
* [[doc:lcl/buttons/tbitbtn.html|TBitBtn doc]]<br />
* [[TButton/ja]]<br />
* [[TSpeedButton]]<br />
* [[TColorButton]]<br />
<br />
{{LCL Components/ja}}</div>Aribenhttps://wiki.freepascal.org/Additional_tab/jaAdditional tab/ja2024-03-24T14:22:40Z<p>Ariben: </p>
<hr />
<div>{{ Additional tab}}<br />
<br />
'''Additional タブ''は[[Component Palette/ja]]に含まれ、よく用いられる、追加のコンポーネントである。<br />
<br />
[[Image:Component_Palette_Additional.png|width="100%"]]<br />
<br />
{| class="wikitable sortable" <br />
|-<br />
! Icon !! コンポーネント !! 内容 !! オンラインドキュメント<br />
|-<br />
| [[image:tbitbtn.png]] || [[TBitBtn/ja]] || キャプションとオプション画像を持つボタン<br />
|| [http://lazarus-ccr.sourceforge.net/docs/lcl/buttons/tbitbtn.html Link]<br />
|-<br />
| [[image:tspeedbutton.png]] || [[TSpeedButton/ja]] || [[TBitBtn]]に類似するが、キーボードフォーカスを受けない。通常ツールバー様のパネルで用いられる<br />
|| [http://lazarus-ccr.sourceforge.net/docs/lcl/buttons/tspeedbutton.html Link]<br />
|-<br />
| [[image:tstatictext.png]] || [[TStaticText/ja]] || [[TLabel]]のようにテキストを表示するが、キーボードフォーカスを受ける<br />
|| [http://lazarus-ccr.sourceforge.net/docs/lcl/stdctrls/tstatictext.html Link] <br />
|-<br />
| [[image:timage.png]] || [[TImage/ja]] || 画像を表示する (gif, jpg, bmp, png)<br />
|| [http://lazarus-ccr.sourceforge.net/docs/lcl/extctrls/timage.html Link]<br />
|-<br />
| [[image:tshape.png]] || [[TShape/ja]] || 三角形/四角形/円を描く<br />
|| [http://lazarus-ccr.sourceforge.net/docs/lcl/extctrls/tshape.html Link]<br />
|-<br />
| [[image:tbevel.png]] || [[TBevel/ja]] || 深さを示唆するボーダー。フォーム要素を光学的にグループ化するのに便利。<br />
|| [http://lazarus-ccr.sourceforge.net/docs/lcl/extctrls/tbevel.html Link]<br />
|-<br />
| [[image:tpaintbox.png]] || [[TPaintBox/ja]] || [[TCanvas]]でエリアを描く<br />
|| [http://lazarus-ccr.sourceforge.net/docs/lcl/extctrls/tpaintbox.html Link]<br />
|-<br />
| [[image:tnotebook.png]] || [[TNotebook/ja]] || 実際のノートブックのようなページを保持するコンテナ。[[TPageControl]]に類似してるが、タブはない。<br />
|| [http://lazarus-ccr.sourceforge.net/docs/lcl/extctrls/tnotebook.html Link]<br />
|-<br />
| [[image:tlabelededit.png]] || [[TLabeledEdit/ja]] || [[TEdit]] と [[TLabel]]の組み合わせ<br />
|| [http://lazarus-ccr.sourceforge.net/docs/lcl/extctrls/tlabelededit.html Link] <br />
|-<br />
| [[image:tsplitter.png]] || [[TSplitter/ja]] || 隣接するコントロールのサイズ変更ツール<br />
|| [http://lazarus-ccr.sourceforge.net/docs/lcl/extctrls/tsplitter.html Link]<br />
|-<br />
| [[image:ttrayicon.png]] || [[TTrayIcon/ja]] || システムトレイのアプリケーションのアイコン<br />
|| [http://lazarus-ccr.sourceforge.net/docs/lcl/extctrls/ttrayicon.html Link]<br />
|-<br />
| [[image:tcontrolbar.png]] || [[TControlBar/ja]] ||ユーザー設定可能なツールバー用のコンテナ<br />
|| [http://lazarus-ccr.sourceforge.net/docs/lcl/colorbox/tcontrolbar.html Link]<br />
|-<br />
| [[image:tflowpanel.png]] || [[TFlowPanel/ja]] || 固定された位置を持たないが、コンテナのサイズが変更されると「流れる」ことができるコンポーネントのためのコンテナ<br />
|| [http://lazarus-ccr.sourceforge.net/docs/lcl/colorbox/tflowpanel.html Link]<br />
|-<br />
| [[image:tmaskedit.png]] || [[TMaskEdit/ja]] || 特定の入力マスクを遵守させることができる[[TEdit]]の変種<br />
|| [http://lazarus-ccr.sourceforge.net/docs/lcl/maskedit/tmaskedit.html Link]<br />
|-<br />
| [[image:tchecklistbox.png]] || [[TCheckListBox/ja]] || [[TListBox]]に類似していますが、アイテムには[[TCheckBox]]が添付されている。<br />
|| [http://lazarus-ccr.sourceforge.net/docs/lcl/checklst/tchecklistbox.html Link]<br />
|-<br />
| [[image:tscrollbox.png]] || [[TScrollBox/ja]] || スクロールするコンテナ<br />
|| [http://lazarus-ccr.sourceforge.net/docs/lcl/forms/tscrollbox.html Link]<br />
|-<br />
| [[image:tapplicationproperties.png]] || [[TApplicationProperties/ja]] || 非表示のアプリケーションプロパティサプライヤ<br />
|| [http://lazarus-ccr.sourceforge.net/docs/lcl/forms/tapplicationproperties.html Link]<br />
|-<br />
| [[image:tstringgrid.png]] || [[TStringGrid/ja]] || 文字列のための2次元グリッド<br />
|| [http://lazarus-ccr.sourceforge.net/docs/lcl/grids/tstringgrid.html Link]<br />
|-<br />
| [[image:tdrawgrid.png]] || [[TDrawGrid/ja]] || コードによりセルが描かれる2次元グリッド<br />
|| [http://lazarus-ccr.sourceforge.net/docs/lcl/grids/tdrawgrid.html Link]<br />
|-<br />
| [[image:tpairsplitter.png]] || [[TPairSplitter/ja]] || [[TSplitter]]と同様に動作し、各側に他のコントロール用のパネル状のコンテナが組み合わされています。<br />
|| [http://lazarus-ccr.sourceforge.net/docs/lcl/pairsplitter/tpairsplitter.html Link]<br />
|-<br />
| [[image:tcolorbox.png]] || [[TColorBox/ja]] || 色を選択するための[[TComboBox|Combobox]]<br />
|| [http://lazarus-ccr.sourceforge.net/docs/lcl/colorbox/tcolorbox.html Link]<br />
|-<br />
| [[image:tcolorlistbox.png]] || [[TColorListBox/ja]] || [[TListBox]] to choose a color <br />
|| [http://lazarus-ccr.sourceforge.net/docs/lcl/colorbox/tcolorlistbox.html Link]<br />
|-<br />
| [[image:tvaluelisteditor.png]] || [[TValueListEditor/ja]] || List of property names with editable values <br />
|| [http://lazarus-ccr.sourceforge.net/docs/lcl/colorbox/tvaluelisteditor.html Link]<br />
|}<br />
<br />
==以下も参照のこと ==<br />
* [http://lazarus-ccr.sourceforge.net/docs/lcl/extctrls/index-4.html extctrls doc]<br />
<br />
{{NavComponentPalette/ja}}<br />
<br/></div>Aribenhttps://wiki.freepascal.org/Additional/jaAdditional/ja2024-03-24T09:15:33Z<p>Ariben: Blanked the page</p>
<hr />
<div></div>Aribenhttps://wiki.freepascal.org/source_code_editor/jasource code editor/ja2024-03-22T01:19:42Z<p>Ariben: Created page with "{{Japanese Menu}} A '''ソースコードエディタ''' is an editor program particularly addressing programmers’ demands, either exclusively (..."</p>
<hr />
<div>{{Japanese Menu}}<br />
<br />
<br />
A '''[[Source code|ソースコード]]エディタ''' is an [[Editor|editor]] program particularly addressing programmers’ demands, either exclusively (cf. [[IDE]]) or as part of a general-purpose suite.<br />
<br />
== 特徴 ==<br />
A source code editor is not a ''text processor'', instead:<br />
* It uses an single <tt>mono space</tt> western [[#Font|font]] of one size and with uniform spacing [e.g. ''Courier'' is such a font].<br />
* Lines have a unique [[#Line Height|height]] and spacing.<br />
* There are no hidden [[#Text Attributes|attributes]] added to the stored text.<br />
* Text attributes are used only for [[#syntax highlighting]] or similar predefined purposes.<br />
* All text is left justified. Indentation is done with [[#Tabstops|tabstops]].<br />
* [[#WordWrap|Long lines]] are not automatically wrapped on hyphens (hyphenated word) or syllable boundaries.<br />
* There is no document, page or paragraph formatting or [[#Layout|layout]].<br />
<br />
Some common and desirable features are:<br />
* adjustable [[#Tabstops|tab expansion]].<br />
* [[#Margin|right margin]] marker (soft).<br />
* [[#Blocks|block selection]] and processing (single block).<br />
* read-only, insert and overwrite [[#Input Modes|input modes]].<br />
* rich choice of keyboard [[#Commands|commands]].<br />
* [[#Scrolling|scrollbars]], mouse and mouse-wheel support.<br />
* [[#Undo and Redo|undo/redo]] support.<br />
* [[#Clipboard|clipboard]] support.<br />
* line number and special marker display ([[#Gutter|gutter]]).<br />
<br />
Additional useful extensions:<br />
* [[#syntax highlighting|syntax highlighting]].<br />
* [[#bookmarks|bookmarks]].<br />
* hyperlink and block [[#navigation|navigation]].<br />
* [[#code completion|code completion]].<br />
* visualization of [[#white characters|white characters]].<br />
* display and editing of embedded [[#Unicode literals|Unicode literals]].<br />
* [[#macro|macro]] capabilities.<br />
* block [[#folding|folding]].<br />
* [[#block movement|block movement]].<br />
* [[#EOL adjustment|EOL adjustment]].<br />
* [[#tab replacement|tab replacement]].<br />
* smart [[#indentation|indentation]].<br />
* multiple text [[#windows]], easy content switch, multiple display of same text source.<br />
* persistent user [[#settings|settings]].<br />
* [[#context menu|context menu]].<br />
<br />
Also desireable, but not for source code editing:<br />
* [[#word wrap|word wrap]].<br />
* [[#Unicode|Unicode]] support.<br />
* [[#hexdump|hexdump]] of binary sources.<br />
<br />
== Unsorted ==<br />
(to be categorized)<br />
<br />
=== Font ===<br />
For traditional and performance reasons, a mono space font shall be used. This allows to manage the display in form of a grid, with easy mapping between screen coordinates and character indices.<br />
Most compilers only accept ASCII code, other characters can be used only in comments.<br />
<br />
Of course support for other character sets (input and display) and input orientation (right-to-left) can be added - by persons with according knowledge and skills. I have no idea how to e.g. mix RTL string literals with LTR program code. OTOH I'm not comfortable with ASCII text myself, as are many more non-English speakers. I'll support any (every?) attempt to remove language barriers from [[SynEdit]], but cannot contribute many ideas or techniques to this subject.<br />
<br />
== See also ==<br />
* [[vim]]</div>Aribenhttps://wiki.freepascal.org/IDE_Window:_Object_Inspector/jaIDE Window: Object Inspector/ja2024-03-22T01:11:36Z<p>Ariben: /* デフォルトに設定 */</p>
<hr />
<div>{{IDE Window: Object Inspector}}<br />
<br />
{{Japanese Menu}}<br />
<br />
<br />
<br />
= オブジェクトインスペクタ =<br />
<br />
[[File:ObjectInspector ja.png|right]]<br />
<br />
「オブジェクトインスペクタ」ウィンドウを使うと、オブジェクトのプロパティを調査したり編集したりできる。ここで言うオブジェクトとは、TFormやTButton、TOpenDialogなどのTPersistentの派生である。<br />
<br />
上部には、現在編集中のデザイナフォーム(またはデータモジュール、フレームなど)のコンポーネントを表示するツリーがある。<br />
<br />
オブジェクトインスペクタの大部分は、「Properties」、「Events」、「Favorites」と呼ばれる3つのプロパティグリッドで構成されている。各プロパティグリッドは、選択されたコンポーネントの公開プロパティのサブセットを表示する。<br />
<br />
オブジェクトインスペクタは、自分のプログラムのデバッグに役立つツールである。自分のプログラムにオブジェクトインスペクタを追加する方法は、examples/objectinspectorで示されている。<br />
<br />
= キーボードショートカット =<br />
{| class="wikitable"<br />
|-<br />
! ショートカット !! 内容<br />
|-<br />
| Up, Down ||行の移動<br />
|-<br />
| Alt + Left || 配下の項目を隠す<br />
|-<br />
| Alt + Right || 配下の項目を表示する<br />
|-<br />
| Ctrl + Enter || 次の候補を表示<br />
|}<br />
<br />
キーボードを使用して、Propaty名の高速検索と編集を行うことができる。<br />
例えば、、フォームのCaption(キャプション)とWidth(幅)のプロパティを変更したい場合の手順は以下の通りである:<br />
<br />
* フォームを選択する。<br />
* オブジェクトインスペクタに移動する(Property値列に入力カーソルが表示される)。<br />
* Tabキーを押してProperty名列に切り替える(入力カーソルが値列から消える)。<br />
* 「caption」とタイプする。「Caption」Property行が検索されてフォーカスされる。<br />
* TabまたはEnterキーを押して、プロパティ値を編集する。<br />
* 再度、Tabキーを押してプロパティ名列に切り替える。<br />
* 「width」とタイプします。「Width」行が検索される。<br />
* TabまたはEnterキーを押して、値を編集する。<br />
<br />
もしPropaty名を間違えてしまった場合、Escキーを押して入力をキャンセルし、再度タイプし直すことができる。または、Backspaceキーを使用して、最後の数文字を削除することも可能である。<br />
<br />
= オブジェクトインスペクタのポップアップメニュー =<br />
<br />
[[File:ObjectInspectorPopUpMenu_ja.png|right]]<br />
<br />
オブジェクトインスペクタのPropatyタブで右クリックすると、オブジェクトインスペクタのポップアップメニューが表示される。ポップアップメニューに含まれる項目は以下の通りである:<br />
<br />
== デフォルトに設定 ==<br />
<br />
プロパティ値をデフォルトにする。例えば:<br />
property Position: TPosition read FPosition write SetPosition default poDesigned;<br />
ここで poDesigned がデフォルトである。<br />
<br />
注意: すべてのプロパティがデフォルト値を持っているわけではない。'''stored'''関数で定義されたデフォルト値はこの関数により無視される。<br />
<br />
== お気に入りに追加 ==<br />
<br />
Add the property to the Favorites tab of the Object Inspector.<br />
<br />
== 制限されたプロパティを見る ==<br />
<br />
Opens the [[IDE Window: Restriction Browser|Restriction Browser]].<br />
<br />
== 元に戻す ==<br />
<br />
Discard changes to the property edit field and restore the value of the current property. Do not confuse this with the value from the disk.<br />
<br />
== Cursorの宣言に移動 ==<br />
<br />
Jump to the source declaration of the property. This will be the last one. For example TForm.Left is published in the class TForm and defined in TControl. You can jump easily to the other declaration, by doing a find declaration on the name again and again, until you are the lowest definition (Alt+Up or Ctrl+LeftClick). You can jump back with Ctrl+H.<br />
<br />
== コンポーネントツリーを表示 ==<br />
<br />
Show or hide the component tree at the top of the Object Inspector.<br />
<br />
== Show Property Filter ==<br />
<br />
Show or hide the Properties (filter) edit field above the Properties tab of the Object Inspector.<br />
<br />
== ヒントを表示 ==<br />
<br />
Enable or disable the showing of hints. Hints are shown, when the mouse stops for a few seconds over a property.<br />
<br />
== 情報箱を表示 ==<br />
<br />
Enable or disable the showing of the yellow background Information Box at the bottom of the Object Inspector. The Information Box describes the currently highlighted property and may contain links to related properties and the package to which the component belongs. If the box is not big enough to show the full description, it can be scrolled.<br />
<br />
== ステータスバーを表示 ==<br />
<br />
Enable or disable the showing of the Status Bar on the last line at the bottom of the Object Inspector.<br />
<br />
== オプション ==<br />
<br />
Configure some options of the Object Inspector including the colours used.</div>Aribenhttps://wiki.freepascal.org/Working_With_TSQLQuery/jaWorking With TSQLQuery/ja2024-03-20T14:03:54Z<p>Ariben: </p>
<hr />
<div>{{Working With TSQLQuery}}<br />
<br />
{{Infobox databases/ja}}<br />
<br />
{{Japanese Menu}}<br />
<br />
<br />
== 一般的な事柄 ==<br />
TSQLQuery is an object that can embody a dataset coming from a database (RDBMS that uses SQL, such as Firebird, MS SQL Server, Oracle...). Using a SELECT SQL statement in the TSQLQuery's SQL property, you can determine what data is retrieved from the database into the dataset. When the dataset is changed by the program (or user), the changes can be submitted back to the database.<br />
<br />
A TSQLQuery can also be used to directly modify data: if you specify the desired INSERT, UPDATE, DELETE etc SQL statement in the SQL property and call the ExecSQL method of the TSQLQuery, the query object will send the SQL to the database without retrieving any results.<br />
<br />
Apart from its use in FPC, Lazarus also provides a component: [[TSQLQuery]] [[image:tsqlquery.png]] <br />
<br />
== 公式ドキュメント ==<br />
See [http://www.freepascal.org/docs-html/fcl/sqldb/tsqlquery.html TSQLQuery documentation]<br />
<br />
A lot of context-sensitive documentation is now available in Lazarus. Unfortunately, TSQLQuery does not appear in the index of Lazarus 1.0 help. If you place your cursor on TSQLQuery methods and properties, try pressing F1 to see if that code is documented; e.g. this will work:<br />
<syntaxhighlight lang=pascal><br />
var<br />
Q: TSQLQuery<br />
...<br />
Q.Open; //<--- place cursor on Open and press F1<br />
</syntaxhighlight><br />
<br />
== 一般的に用いられるコントロール ==<br />
The dataset returned by TSQLQuery can conveniently be ''viewed'' with an instance of [[TDBGrid]], but it is not very suitable for ''editing'' the data in the individual fields and cells.<br />
For this purpose you need to place some Data-Aware single-field controls such as [[TDBEdit]] on your form, and set their DataSource poperty to the data source being used. The DataField property should be set to a named field (eg 'IDENTITY') or to some expression that returns a suitable string.<br />
<br />
Addition of a [[TDBNavigator]] toolbar makes it very easy to navigate through the records, and to select records for editing. When a record is selected by the toolbar or by moving the mouse through the data grid, the data for the relevant row and column appear in the TDBEdit box and if the 'Edit' button is clicked, the contents in the Edit box can be modified. Clicking on the 'Post' button confirms the change, or clicking on the 'Cancel' button cancels the changes.<br />
<br />
In general, the process is as follows:<br />
# Drop a [[TSQLQuery]] on a form/datamodule, and set the ''Database'', ''Transaction'' and ''SQL'' properties.<br />
# Drop a [[TDataSource]] component, and set its ''DataSet'' property to the TSQLQuery instance.<br />
# Drop a [[TDBGrid]] on the form and set its ''DataSource'' property to the TDataSource instance.<br />
# Optionally, drop a TDBNavigator instance on the form, and set its ''Datasource'' property to the TDatasource instance.<br />
After this, the ''Active'' property can be set to ''True'', and it should be possible to see the data retrieved by the query.<br />
(provided both the ''TSQLConnection'' and ''TSQLTransaction'' components are active)<br />
<br />
== データを更新する == <br />
<br />
If you need to be able to DELETE or otherwise modify records, your database table should either<br />
# contain one PRIMARY KEY column.<br />
# have a set of fields that uniquely determine the record. Normally, they should be part of a unique index. This is not required, but will speed up the queries quite a lot<br />
<br />
If there is no primary field, or no fields that uniquely determine your record, then a primary key field should be added.<br />
This is done preferably when the table structure is designed, at CREATE time, but can be added at a later time.<br />
<br />
For instance the following example code in your MySQL client will add a unique index to your table:<br />
<syntaxhighlight lang="sql"><br />
alter table testrig <br />
add column autoid int <br />
primary key auto_increment;<br />
</syntaxhighlight><br />
Adding this field will not hurt, and will allow your applications to update the field.<br />
<br />
== キャッシュされた更新 ==<br />
The ''TSQLQuery'' component caches all updates. That is, the updates are not sent immediately to the database, but are kept in memory till the ''ApplyUpdates'' method is called. At that point, the updates will be transformed to SQL update statements, and will be applied to the database. If you do not call ''ApplyUpdates'', the database will not be updated with the local changes.<br />
<br />
== プライマリキーフィールド ==<br />
<br />
When updating records, ''TSQLQuery'' needs to know which fields comprise the primary key that can be used to update the record,<br />
and which fields should be updated: based on that information, it constructs an SQL UPDATE, INSERT or DELETE command.<br />
<br />
The construction of the SQL statement is controlled by the ''UsePrimaryKeyAsKey'' property and the ''ProviderFlags'' properties.<br />
<br />
The ''Providerflags'' property is a set of 3 flags:<br />
; pfInkey: The field is part of the primary key<br />
; pfInWhere: The field should be used in the WHERE clause of SQL statements.<br />
; pfInUpdate: Updates or inserts should include this field.<br />
<br />
By default, ''ProviderFlags'' consists of ''pfInUpdate'' only.<br />
<br />
If your table has a primary key (as described above) then you only need to set the ''UsePrimaryKeyAsKey'' property to ''True'' and<br />
everything will be done for you. This will set the ''pfInKey'' flag for the primary key fields. <br />
<br />
If the table doesn't have a primary key index, but does have some fields that can be used to uniquely identify the record, then<br />
you can include the ''pfInKey'' option in the ''ProviderFlags'' property all the fields that uniquely determine the record.<br />
<br />
The ''UpdateMode'' property will then determine which fields exactly will be used in the WHERE clause:<br />
<br />
; upWhereKeyOnly: When ''TSQLQuery'' needs to construct a WHERE clause for the update, it will collect all fields that have the ''pfInKey'' flag in their ''ProviderFlags'' property set, and will use the values to construct a WHERE clause which uniquely determines the record to update -- normally this is only needed for an UPDATE or DELETE statement.<br />
<br />
; upWhereChanged: In addition to the fields that have ''pfInKey'' in the ''ProviderFlags'' property, all fields that have ''pfInWhere'' in their ''ProviderFlags'' and that have changed, will also be included in the WHERE clause.<br />
<br />
; upWhereAll: In addition to the fields that have ''pfInKey'' in the ''ProviderFlags'' property, all fields that have ''pfInWhere'' in their ''ProviderFlags'', will also be included in the WHERE clause.<br />
<br />
== 更新をコントロールする ==<br />
It is possible to specify which fields should be updated: As mentioned above: Only fields that have ''pfInUpdate'' in their ''ProviderOptions'' property will be included in the SQL UPDATE or INSERT statements. By default, ''pfInUpdate'' is always included in the ''ProviderOptions'' property.<br />
<br />
== SQLをTSQLQueryの中でカスタマイズする ==<br />
Normally TSQLQuery will use generic SQL statements based on properties as discussed above. However, the generic SQL created by sqldb may not be correct for your situation. TSQLQuery allows you to customize SQL statements used for the various actions, to work best in your situation with your database. For this purpose you use the properties ''SQL'', ''InsertSQL'', ''UpdateSQL'' and ''DeleteSQL''.<br />
<br />
All these properties are of type TStringList, a list of strings, that accepts multiple lines of SQL. All four come with a property editor in the IDE. In the IDE, select the property and open the editor by clicking the ellipsis button. In this editor ([[Database_metadata#Lazarus_TSQLQuery_metadata_tool|TSQLQuery metadata tool]]), you may also look up table information etc.<br />
<br />
In code, use for example <tt>InsertSQL.Text</tt> or <tt>InsertSQL.Add()</tt> to set or add lines of SQL statements. One statement may span several lines and ends with a semicolon.<br />
<br />
Also, all four properties accept parameters explained further below.<br />
<br />
===SQL - 基本的なSQLカスタマイゼーション===<br />
The SQL property is normally used to fetch the data from the database. The generic SQL for this property is <tt>SELECT * FROM fpdev</tt> where <tt>fpdev</tt> is the table as set in the database.<br />
<br />
The dataset returned by the generic SQL statement will be kind of rough. If you show the result in a TDBGrid, the order of the records may seem random, the order of the columns may not be what you want and the field names may be technically correct but not user friendly. Using customized SQL you can improve this.<br />
For a table called fpdev with columns id, UserName and InstEmail, you could do something like this:<br />
<syntaxhighlight lang="sql">SELECT id AS 'ID', UserName AS 'User', InstEmail AS 'e-mail' FROM fpdev ORDER BY id;</syntaxhighlight><br />
<br />
The dataset that results from the above query uses the field names as given in the query (ID, User and e-mail), the column order as given in the query and the records are sorted by their id.<br />
<br />
=== InsertSQL、UpdateSQL、DeleteSQL - パラメータの基本的な使用===<br />
When you assign a SELECT query to an SQLQuery's '''SQL''' property the SQLQuery knows how to get data from the database. <br />
However, when using databound controls such as a DBGrid, SQLQuery will also need to be able to insert, update and delete rows from the database based on the user's actions.<br />
<br />
In order to speed development, SQLQuery can try and deduce the required SQL statements. If the SQL property exists and the '''ParseSQL''' property is true (which it is by default), SQLQuery will try to generate these statements by parsing the '''SQL''' property.<br />
SQLDB stores these statements in the '''InsertSQL''', '''UpdateSQL''' and '''DeleteSQL''' properties.<br />
<br />
However, sometimes the generated statements will not work (e.g. when inserting in tables with auto-increment/autonumber primary keys) or will be very slow. If needed, you can manually assign the statements.<br />
<br />
The statements in the ''InsertSQL'', ''UpdateSQL'' and ''DeleteSQL'' properties accept parameters that represent fields in the dataset. The following rules apply:<br />
* Parameter names must be exactly the same as the field names used in the dataset. The field names in the dataset may be different from the column names in the table, depending on the used select statement (see above).<br />
* Just as parameters in other SQLDB queries, parameter names must be written preceded by a colon.<br />
* For use in update/delete statements, precede the dataset field name with '''OLD_''' ('''strictly uppercase''', at least in Lazarus v. 1.0) to get the value of the record before it was edited instead of the new value.<br />
<br />
If you have a table called fpdev and columns id, UserName and InstEmail, linked to a dataset with fields ID, User and e-mail (see example in select statement), you could write this '''InsertSQL''' query:<br />
<syntaxhighlight lang="sql">INSERT INTO fpdev(id, UserName, InstEmail) VALUES(:ID,:User,:e-mail);</syntaxhighlight><br />
This statement will insert the values of <tt>ID</tt>, <tt>User</tt> and <tt>e-mail</tt> from the current record of the dataset into the respective fields of table <tt>fpdev</tt>.<br />
<br />
This example statement is actually more or less what SQLDB itself would autogenerate. The given statement may result in errors when the <tt>id</tt> field is an auto-increment field in a unique key. Different databases solve this problem in different ways. For example, the following works for MySQL.<br />
<syntaxhighlight lang="sql">INSERT INTO fpdev(id, UserName, InstEmail) VALUES(0,:User,:e-mail)<br />
ON DUPLICATE KEY UPDATE id=LAST_INSERT_ID();</syntaxhighlight><br />
The above statement tries to insert a new record using 0 (zero) for the <tt>id</tt> column. If zero is already used as a key, then a duplicate is detected and the <tt>id</tt> is updated to use the last inserted id. Well, actually an id one increment higher than the last one used.<br />
<br />
For Firebird, if you emulate autoincrement keys [http://www.firebirdfaq.org/faq29/] something like this should work:<br />
<syntaxhighlight lang="sql">INSERT INTO fpdev(UserName, InstEmail) VALUES(:User,:e-mail);(</syntaxhighlight><br />
The statement inserts everything except the primary key and lets the Firebird before insert trigger use a generator/sequence to insert an <tt>id</tt> value for you. <br />
<br />
For an <tt>INSERT</tt> statement you may want to use the current field values of the selected record. For <tt>UPDATE</tt> statements, you will want to use the field values as they were before editing in the <tt>WHERE</tt> clause. As mentioned before, the field values before editing must be written as the field name precede by '''OLD_''' ('''strictly uppercase''', at least in Lazarus v. 1.0). For example, this query:<br />
<syntaxhighlight lang="sql">UPDATE fpdev SET UserName=:User, InstEmail=:e-mail WHERE UserName=:OLD_User;</syntaxhighlight><br />
The above statement updates the <tt>UserName</tt> and <tt>InstEmail</tt> columns of all records where <tt>User</tt> equals the old <tt>User</tt> value.<br />
<br />
We leave it as an exercise to the reader to use the current field values and the old field values in DELETE statements.<br />
<br />
See also the official documentation:<br />
* [http://www.freepascal.org/docs-html/fcl/sqldb/tsqlquery.insertsql.html InsertSQL documentation]<br />
* [http://www.freepascal.org/docs-html/fcl/sqldb/tsqlquery.updatesql.html UpdateSQL documentation]<br />
* [http://www.freepascal.org/docs-html/fcl/sqldb/tsqlquery.deletesql.html DeleteSQL documentation]<br />
<br />
===TSQLQuery.SQLにおけるパラメータ===<br />
In most situations, the SQL property of TSQLQuery will contain the select statement which in most situations doesn't need parameters. However, it can contain them. This allows a very easy and powerful way to filter your records.<br />
<br />
Parameters have the following advantages:<br />
* no need to format your data as SQL text, date etc arguments (i.e. no need to remember how to format a date for MySQL, which might differ from the Firebird implementation; no need to escape text data like ''O'Malley's "SQL Horror"''<br />
* possibly increased performance<br />
* protection against SQL injection attacks<br />
<br />
<br />
The use of parameters may help performance of the database. Most databases support prepared statements, which means that the statement is prepared and cached in the database. A prepared statement can be used more than once and doesn't require parsing and query planning every time it is used, only the parameters are changed each time it is used.<br />
In situations where the same statement is used a large number of times (where only the values of the parameters differ), prepared statements can help performance considerably.<br />
Additionally, SQL injection attacks can be mitigated by use of parameters.<br />
<br />
The ''InsertSQL'', ''UpdateSQL'' and ''DeleteSQL'' properties have predefined parameters for current and old field values. However, the ''SQL'' property does not. You can create your own parameters in the ''Params'' property.<br />
<br />
====Selectクエリの例====<br />
This example shows how to select data using parameters. It also demonstrates using aliases (... AS ...) in SQL.<br />
<syntaxhighlight lang=pascal><br />
sql_temp.sql.text := 'SELECT id AS ''ID'', UserName AS ''User'', InstEmail AS ''e-mail'' FROM fpdev WHERE InstEmail=:emailsearch;'<br />
...<br />
//This will create a parameter called emailsearch.<br />
<br />
//If we want to, we can explicitly set what kind of parameter it is... which might only be necessary if FPC guesses wrong:<br />
//sql_temp.params.parambyname('emailsearch').datatype:=ftWideString<br />
<br />
//We can now fill in the parameter value:<br />
sql_temp.params.parambyname('emailsearch').asstring := 'mvancanneyt@freepascal.org';<br />
...<br />
//Then use your regular way to retrieve data,<br />
//optionally change the parameter value & run it again<br />
</syntaxhighlight><br />
<br />
====Insertクエリの例====<br />
This example shows how to insert a new record into the table using parameters:<br />
<syntaxhighlight lang=pascal><br />
sql_temp.sql.text := 'insert into PRODUCTS (ITEMNR,DESCRIPTION) values (:OURITEMNR,:OURDESCRIPTION)'<br />
...<br />
sql_temp.Params.ParamByName('OURITEMNR').AsString := 'XXXX';<br />
sql_temp.Params.ParamByName('OURDESCRIPTION').AsString := 'description';<br />
sql_temp.ExecSQL;<br />
SQLTransaction1.Commit; //or possibly CommitRetaining, depending on how your application is set up<br />
</syntaxhighlight><br />
<br />
Another way of doing this is something like:<br />
<syntaxhighlight lang=pascal><br />
tsqlquery1.appendrecord(['XXXX', 'description']) <br />
tsqltransaction1.commit; //or commitretaining<br />
</syntaxhighlight><br />
<br />
===フォーマット関数を伴なうクエリ===<br />
Using parameterized queries is the preferred approach, but in some situations the format function can be an alternative. (see warning below). For example, parameters can't be used when you execute statements with the connection's ExecuteDirect procedure (''of course, you can just as well use a query to run the SQL statement in question''). Then this can come in handy:<br />
<br />
<syntaxhighlight lang=pascal><br />
procedure InsertRecord<br />
var<br />
aSQLText: string;<br />
aSQLCommand: string;<br />
begin<br />
aSQLText:= 'INSERT INTO products(item_no, description) VALUES(%d, %s)';<br />
aSQLCommand:= Format(aSQLText, [strtoint(Edit1.Text), Edit2.Text]);<br />
aConnection.ExecuteDirect(aSQLCommand);<br />
aTransaction.Commit;<br />
end;<br />
</syntaxhighlight><br />
<br />
The values of the variables can change and the query values will change with them, just as with parameterized queries.<br />
<br />
The parameter %d is used for integers, %s for strings; etc. See the documentation on the Format function for details.<br />
<br />
{{Warning|Be aware that you may run into issues with text containing ' and dates using this technique!}}<br />
<br />
== 独自のSQLを実行しメタデータを得る ==<br />
If you want to just check some SQL statements, troubleshoot, or get metadata (e.g. list of tables) from the database, you can do so from within the IDE.<br />
In your program, with your T*Connection, transaction, query object etc set up at design-time, go into the SQL property for the query object, then click the ... button.<br />
<br />
You'll see a window with SQL code, and you can run some statements like<br />
<syntaxhighlight lang="sql"><br />
SELECT * FROM EMPLOYEE<br />
</syntaxhighlight><br />
by pressing the play icon:<br />
<br />
[[Image:runsqlstatements.png]]<br />
<br />
You can also get metadata: table names, column names etc (if the sqldb connector supports it but most of them do nowadays):<br />
<br />
[[Image:sqlquerymetadata.png]]<br />
<br />
(See also: [[Database metadata#Lazarus TSQLQuery metadata tool]])<br />
<br />
== 問題解決 ==<br />
=== Logging ===<br />
See here: [[SqlDBHowto#Troubleshooting: TSQLConnection logging]] for more detail.<br />
=== Poor performance ===<br />
* Make sure your database queries are optimized (use proper indexes etc). Use your database tools (e.g. providing query plans) for this.<br />
* See [[#Out of memory errors]] below for possible performance improvements when moving forward through an SQLQuery.<br />
<br />
=== エラーメッセージ ===<br />
=== エラー: メモリが足りない ===<br />
TSQLQuery is a descendant of BufDataset, a dataset that buffers the data it receives into memory. If you retrieve a lot of records (e.g. when looping through them for an export), your heap memory may become full (with records you already looped through) and you will get out of memory errors.<br />
<br />
Although this situation has improved in the FPC development version, a workaround is to tell bufdataset to discard the records you have already read by setting the Unidirectional property to true before opening the query:<br />
<syntaxhighlight lang=pascal><br />
MySQLQuery.UniDirectional:=True;<br />
</syntaxhighlight><br />
<br />
This may also improve performance.<br />
<br />
=== データセットは読み取り専用 ===<br />
This may happen if you specify a query that you know is updatable but FPC doesn't.<br />
<br />
例:<br />
<syntaxhighlight lang="sql"><br />
select p.dob, p.surname, p.sex from people p;<br />
</syntaxhighlight><br />
The SQL parser in FPC is quite simplistic and when it finds a comma or space in the FROM part it considers multiple tables are involved and sets the dataset to read only. To its defense, aliasing tables is usually not done when only one table is involved.<br />
Solution: rewrite the query or specify your own <code>InsertSQL</code>, <code>UpdateSQL</code> and <code>DeleteSQL</code>.</div>Aribenhttps://wiki.freepascal.org/LCL_Components/jaLCL Components/ja2024-03-18T02:45:56Z<p>Ariben: /* Standardタブ */</p>
<hr />
<div>{{LCL Components Langs}}<br />
<br />
{{Japanese Menu}}<br />
<br />
より知りたいコンポーネントを選択されたい:<br />
<br />
==[[Forms]]==<br />
([https://lazarus-ccr.sourceforge.io/docs/lcl/forms/tform.html StdCtrls unit Online Docs]も参照のこと)<br />
<center>[[Image:l-ide-1.png]]</center><br />
<br />
デフォルトでは新しいグラフィカルアプリケーションがプロジェクトに作られるとき、Form1がプロジェクトに加えられる。ツールバーの「New Form」をクリックするか、ファイルメニューの「新規フォーム」を選択することにより、さらにフォームが追加される。<br />
<br />
* [[TForm/ja|TForm]]<br />
<br />
==[[Standard tab/ja|Standard タブ]]==<br />
([http://lazarus-ccr.sourceforge.net/docs/lcl/stdctrls/index-4.html StdCtrls unit Online Docs]も参照のこと)<br />
<center>[[Image:Component_Palette_Standard.png]]</center><br />
<br />
* ポインタ (コンポーネントを選択していないことを示すために使われる)<br />
<br />
* デフォルトではコンポーネントはLCLの一部としてインストールされる: <br />
** [[TMainMenu/ja|TMainMenu]]、[[TPopupMenu/ja|TPopupMenu]]、[[TButton/ja|TButton]]、[[TLabel/ja|TLabel]]、[[TEdit/ja|TEdit]]、[[TMemo/ja|TMemo]]、[[TToggleBox/ja|TTogglBox]]、[[TCheckBox/ja|TCheckBox]]、[[TRadioButton/ja|TRadioButton]]、[[TListBox/ja|TListBox]]、[[TComboBox/ja|TComboBox]]、[[TScrollBar/ja|TScrollBar]]、[[TGroupBox/ja|TGroupBox]]、[[TRadioGroup/ja|TRadioGroup]]、[[TCheckGroup/ja|TCheckGroup]]、[[TPanel/ja|TPanel]]、[[TFrame/ja|TFrame]]、[[TActionList/ja|TActionList]]<br />
<br />
==[[Additional/ja|Additional タブ]]==<br />
(See also the [http://lazarus-ccr.sourceforge.net/docs/lcl/extctrls/index-4.html ExtCtrls unit Online Docs])<br />
<center>[[Image:Component_Palette_Additional.png]]</center><br />
<br />
*Components installed by default as part of the LCL: <br />
** [[TBitBtn]], [[TSpeedButton]], [[TStaticText]], [[TImage]], [[TShape]], [[TBevel]], [[TPaintBox]], [[TNotebook]], [[TLabeledEdit]], [[TSplitter]], [[TTrayIcon]], [[TMaskEdit]], [[TCheckListBox]], [[TScrollBox]], [[TApplicationProperties]], [[TStringGrid]], [[TDrawGrid]], [[TPairSplitter]], [[TColorBox]], [[TColorListBox]], [[TValueListEditor]]<br />
<br />
==[[Common Controls/ja|Common Controls タブ]]==<br />
(See also the [http://lazarus-ccr.sourceforge.net/docs/lcl/comctrls/index-4.html ComCtrls unit Online Docs])<br />
<center>[[Image:Component_Palette_Common_Controls.png]]</center><br />
*Components installed by default as part of the LCL:<br />
**[[TTrackBar]], [[TProgressBar]], [[TTreeView]], [[TListView]], [[TStatusBar]], [[TToolBar]], [[TUpDown]], [[TPageControl]], [[TTabControl]], [[THeaderControl]], [[TImageList]], [[TPopupNotifier]]<br />
<br />
*Controls which are not part of the LCL, but install in this tab:<br />
**[[RichMemo|TRichMemo]]<br />
**[[DateTimeCtrls Package#TDateTimePicker|TDateTimePicker]] (included in Lazarus and installed automatically with make bigide, but not officially part of LCL)<br />
<br />
*Tutorials:<br />
**[[TTreeView]]<br />
<br />
==[[Dialogs/ja|Dialogs タブ]]==<br />
(See also the [http://lazarus-ccr.sourceforge.net/docs/lcl/dialogs/index-4.html Dialogs unit Online Docs])<br />
<center>[[Image:Component_Palette_Dialogs.png]]</center><br />
<br />
* Components installed by default as part of the LCL:<br />
** [[TOpenDialog]], [[TSaveDialog]], [[TSelectDirectoryDialog]],[[TColorDialog]], [[TFontDialog]], [[TFindDialog]], [[TReplaceDialog]], [[TTaskDialog]], [[TOpenPictureDialog]], [[TSavePictureDialog]], [[TCalendarDialog]], [[TCalculatorDialog]], [[TPrinterSetupDialog]], [[TPrintDialog]], [[TPageSetupDialog]]<br />
<br />
*Several useful '''[http://lazarus-ccr.sourceforge.net/index.php?wiki=DialogExamples Dialog]''' procedures or functions don't appear on the palette, but are easily used as direct calls from your source program.<br />
<br />
==[[Data Controls/ja|Data Controls タブ]]== <br />
Data-aware components, which largely replicate the Standard and Additional groups but are applicable to databases:<br />
<br />
(See also the [http://lazarus-ccr.sourceforge.net/docs/lcl/dbctrls/index-4.html DBCtrls unit Online Docs])<br />
<center>[[Image:Component_Palette_Data Controls.png]]</center><br />
* Components installed by default as part of the LCL:<br />
** [[TDBNavigator/ja|TDBNavigator]], [[TDBText/ja|TDBText]], [[TDBEdit/ja|TDBEdit]], [[TDBMemo/ja|TDBMemo]], [[TDBImage/ja|TDBImage]], [[TDBListBox/ja|TDBListBox]], [[TDBLookupListBox/ja|TDBLookupListBox]], [[TDBComboBox/ja|TDBComboBox]], [[TDBLookupComboBox/ja|TDBLookupComboBox]], [[TDBCheckBox/ja|TDBCheckBox]], [[TDBRadioGroup/ja|TDBRadioGroup]], [[TDBCalendar/ja|TDBCalendar]], [[TDBGroupBox/ja|TDBGroupBox]], [[TDBGrid/ja|TDBGrid]]<br />
<br />
* Also on this tab:<br />
** [[DateTimeCtrls Package#TDBDateTimePicker|TDBDateTimePicker]], which is included in Lazarus and installed automatically with make bigide, but not officially part of LCL.<br />
<br />
==[[Data Access/ja|Data Access タブ]]==<br />
Tha palette '''Data Access''' contains components for access to local and in-memory database tables.<br />
<center>[[Image:Component_Palette_Data Access.png]]</center><br />
* Components installed by default<br />
** [[TDataSource]], [[TBufDataset]], [[TCSVDataSet]], [[TSdfDataSet]], [[TFixedFormatDataSet]], [[TDbf]], [[TParadox]], [[TMemDataset]]<br />
* Also on this page:<br />
** TSqliteDataset, TSqliteDataset<br />
<br />
==[[System/ja|System タブ]]==<br />
<center>[[Image:Component_Palette_System.png]]</center><br />
<br />
* Components installed by default:<br />
** [[TTimer]], [[TIdleTimer]], [[TLazComponentQueue]], [[THTMLHelpDatabase]], [[THTMLBrowserHelpViewer]], [[TAsyncProcess]], [[TProcessUTF8]], [[TProcess|wiki]], [[TSimpleIPCClient]], [[TSimpleIPCServer]], [[TXMLConfig]], [[TEventLog]]<br />
* Also on this tab:<br />
** [[TCHMHelpDatabase]] and [[TLHelpConnector]], included in Lazarus and installed automatically with make bigide<br />
<br />
==[[SQLdb_tab/ja|SQLdb タブ]]==<br />
Non-visible components for access to "large" database systems. <br />
<br />
<center>[[Image:Component_Palette_SQLdb.png]]</center><br />
<br />
* Installed components:<br />
** [[TSQLQuery/ja]], [[TSQLTransaction/ja]], [[TSQLScript/ja]], [[TSQLConnector/ja]], [[TMSSQLConnection/ja]], [[TSybaseConnection/ja]], [[TPQConnection/ja]], [[TPQTEventMonitor/ja]], [[TOracleConnection/ja]], [[TODBCConnection/ja]], [[TMySQL50Connection/ja]], [[TMySQL51Connection/ja]], [[TMySQL55Connection/ja]], [[TMySQL56Connection/ja]], [[TMySQL57Connection/ja]], [[TSQLite3Connection/ja]], [[TIBConnection/ja]], [[TFBAdmin/ja]], [[TFBEventMonitor/ja]], [[TSQLDBLibraryLoader/ja]]<br />
* No longer installed by default in 1.8.4.<br />
** [[TMySQL40Connection/ja]], [[TMySQL41Connection/ja]]<br />
<br />
==[[Misc/ja|Misc タブ]]== <br />
<center>[[Image:Component_Palette_Misc.png]]</center><br />
* Components installed by default:<br />
** [[TColorButton]], [[TSpinEdit]], [[TFloatSpinEdit]], [[TArrow]], [[TCalendar]], [[TEditButton]], [[TFileNameEdit]], [[TDirectoryEdit]], [[TDateEdit]], [[TCalcEdit]], [[TFileListBox]], [[TButtonPanel]], [[TShellTreeView]], [[TShellListView]], [[TXMLPropStorage]], [[TINIPropStorage]], [[TJsonPropStorage]], TIDEDialogLayoutStorage<br />
<br />
==[[LazControls/ja|LazControls タブ]]==<br />
The '''LazControls tab''' lists various (non related) Lazarus-specific components. They are needed by the IDE but can be used also by other projects.<br />
<br />
<center>[[Image:Component_Palette_LazControls.png]]</center><br />
<br />
* Components installed:<br />
** [[TCheckBoxThemed]], [[TDividerBevel]], [[TExtendedNotebook]], [[LazControls#TListFilterEdit|TListFilterEdit]], [[LazControls#TListViewFilterEdit|TListViewFilterEdit]], [http://www.pp4s.co.uk/main/tu-form-level-graph.html TLvlGraphControl], [[TShortPathEdit]], [[TSpinEditEx]], [[TFloatSpinEditEx]], [[LazControls#TTreeFilterEdit|TTreeFilterEdit]], [[TExtendedTabControl]]<br />
<br />
==[[RTTI/ja|RTTI タブ]]==<br />
Specialized components for use with [[RTTI controls|runtime type information]].<br />
<br />
<center>[[Image:Component Palette RTTI.png]]</center><br />
<br />
* Installed components:<br />
** [[TTIEdit]], [[TTIComboBox]], [[TTIButton]],[[TTICheckBox]], [[TTILabel]], [[TTIGroupBox]], [[TTIRadioGroup]], [[TTICheckGroup]], [[TTICheckListBox]], [[TTIListBox]], [[TTIMemo]], [[TTICalendar]], [[TTIImage]],[[TTIFloatSpinEdit]], [[TTISpinEdit]], [[TTITrackBar]], [[TTIProgressBar]], [[TTIMaskEdit]], [[TTIColorButton]], [[TMultiPropertyLink]], [[TTIPropertyGrid]], [[TTIGrid]]<br />
<br />
== [[SynEdit_tab/ja|SynEdit tab]] ==<br />
SynEdit is an advanced multi-line edit control, which is integrated into the Lazarus. It is the code editor of the Lazarus IDE and is available in the directory "lazarus/components/synedit". It supports Syntax Highlighting, code completion, code folding and includes exporters for html, tex and rtf. It is a fully custom drawn component, meaning that it doesn't wrap native controls of each platform and that no external library is required; this make SynEdit a crossplatform component. Note that the SynEdit available with Lazarus is a fork of the original SynEdit for Borland Delphi, Kylix and C++Builder which can be found in [http://synedit.sourceforge.net synedit at sourceforge]<br />
<br />
<center>[[Image:Component_Palette_SynEdit.png]]</center><br />
<br />
* Components installed by default:<br />
** [[TSynEdit]], [[TSynCompletion]], [[TSynAutoComplete]], [[TSynMacroRecorder]], [[TSynExporterHTML]], [[TSynPluginSyncroEdit]], [[TSynPasSyn]], [[TSynFreePascalSyn]], [[TSynCppSyn]], [[TSynJavaSyn]], [[TSynJSSyn]], [[TSynPerlSyn]], [[TSynHTMLSyn]], [[TSynXMLSyn]], [[TSynLFMSyn]], [[TSSynDiffSyn]], [[TSynUNIXShellScriptSyn]], [[TSynCssSyn]], [[TSynPHPSyn]], [[TSynTeXSyn]], [[TSynSQLSyn]], [[TSynPythonSyn]], [[TSynVBSyn]], [[TSynAnySyn]], [[TSynMultiSyn]], [[TSynBatSyn]], [[TSynIniSyn]], [[TSynPoSyn]]<br />
** Additional highlighters are available on https://sourceforge.net/p/lazarus-ccr/svn/HEAD/tree/components/extrasyn/. This package can also be installed via [[Online_Package_Manager|Online package manager]]. They are collected in a separate palette '''SynEdit Highlighters'''.<br />
<br />
== [[Chart_tab/ja|Chart tab]] ==<br />
The '''Chart tab''' lists components for use with graphs and charts from the [[TAChart]] package. They are not part of the LCL, but most of them are installed by default.<br />
<br />
<center>[[Image:Component_Palette_Chart.png]]</center><br />
<br />
* Components installed by default<br />
** [[TChart]], [[TAChart_documentation#List_source|TListChartSource]], [[TAChart_documentation#Random_source|TRandomChartSource]], ,[[TAChart_documentation#User-defined_source|TUserDefinedChartSource]], [[TAChart_documentation#Calculated_source|TCalculatedChartSource]], [[TAChart_documentation#Database_source|TDbChartSource]], [[TAChart_documentation#Tools|TChartToolset]], [[TAChart_documentation#Axis_transformations|TChartAxisTransformations]], [[TAChart_documentation#ChartStyles|TChartStyles]], [[TAChart_documentation#Legend_panel|TChartLegendPanel]], [[TAChart_documentation#Scroll_bars|TChartNavScrollBar]], [[TAChart_documentation#Navigation_panel|TChartNavPanel]], [[TAChart_documentation#Interval_source|TIntervalChartSource]], [[TAChart_documentation#Date-time_interval_source|TDateTimeIntervalChartSource]], [[TAChart_documentation#Chart_listbox|TChartListBox]], [[TAChart_documentation#Linked_extents|TChartExtentLink]], [[TAChart_documentation#Chart_image_list|TChartImageList]], [[TAChart_documentation#Chart_image_list|TChartCombobox]],<br />
* Components installed only if other packages are available:<br />
**[[TAChart_documentation#AggPas_drawer|TChartGUIConnectorAggPas]], [[TAChart_documentation#BGRABitmap_drawer|TChartGUIConnectorBGRA]]<br />
<br />
== [[IPro_tab/ja|iPro tab]] ==<br />
The '''IPro''' palette lists components related to display of html pages. They do not belong to the IDE but are needed by the IDE to show the html-formatted popup coding hints and the chm help files.<br />
<br />
<center>[[Image:Component_Palette_IPro.png]]</center><br />
<br />
* Components installed:<br />
** [[TIpFileDataProvider]], [[TIpHtmlDataProvider]], [[TIpHttpDataProvider]], [[TIpHtmlPanel]]</div>Aribenhttps://wiki.freepascal.org/TActionList/jaTActionList/ja2024-03-17T14:25:30Z<p>Ariben: </p>
<hr />
<div>{{TActionList}}<br />
<br />
{{ Japanese Menu }}<br />
<br />
'''TActionList'''[[image:tactionlist.png]]コンポーネントは、[[TAction]]コンポーネントのコンテナである。ボタン、メニュー、ダイアログ、コントロールのActionプロパティでTActionを使用すると、マウスクリック、メニュー選択、ダイアログ選択などの効果を1つのイベントハンドラで中央集約することができる。<br />
<br />
TForm上でTActionListを使用するには、[[Component Palette/ja|コンポーネントパレット]]の[[Standard tab/ja|Standardタブ]]でそれを選択し、フォーム上でクリックして配置する。<br />
<br />
;画像: TActionListの含まれるTActionsに対応する画像を保持できる[[TImageList]]へのリンク。<br />
;状態: <br />
:;asNormal: TActionsがホットキーなどで呼び出された場合の通常の処理。<br />
:;asSuspended: 呼び出し時に応答せず、ただしTAction.Enabledは変更されない<br />
:;asSuspendedEnabled: 呼び出し時に応答せず、ただしすべてのTAction.Enabledは''true''に設定される<br />
<br />
TActionListをダブルクリックすると、TActionListエディタが表示され、新しいTActionを追加できます。アクションリストエディタで右クリックすると、ローカルメニューが表示される。[[TStandardAction]]は{{keypress|Ctrl+Ins}}でも利用可能である。<br />
<br />
[[image:actionlist-editor.png]]<br />
<br />
== 以下も参照のこと ==<br />
* [[doc:lcl/actnlist/tactionlist.html|TActionList documentation]]<br />
* [[TAction]], [[TActionLink]], [[TActionListEnumerator]], [[TContainedAction]], [[TCustomAction]], [[TCustomActionList]], [[TShortCutList]]<br />
* [[TStandardAction]]<br />
<br />
{{LCL Components/ja}}</div>Aribenhttps://wiki.freepascal.org/TFrame/jaTFrame/ja2024-03-17T14:22:41Z<p>Ariben: </p>
<hr />
<div>{{TFrame}}<br />
<br />
{{ Japanese Menu }}<br />
<br />
'''TFrame''' [[image:tframe.png]]は、コンポーネントの名前付きコンテナであり、TFormと非常に似ている。ユニークな機能として、デザイナーに埋め込むことができる。フォームと同様に、コードは.pasファイルに、デザインは対応する.lfmファイルに保存される。<br />
<br />
== 以下も参照のこと ==<br />
* [[doc:lcl/forms/tframe.html|TFrame doc]]<br />
* [[Frames|Usage of frames]]<br />
* [[TBevel]]<br />
* [[TPanel]]<br />
<br />
{{LCL Components/ja}}</div>Aribenhttps://wiki.freepascal.org/TPanel/jaTPanel/ja2024-03-17T14:21:04Z<p>Ariben: </p>
<hr />
<div>{{TPanel}}<br />
{{ Japanese Menu }}<br />
<br />
'''TPanel''' [[image:tpanel.png]]は、フォーム上にパネルを作成するコンポーネントである。TPanelはTWinControlの派生であり、[[Component Palette/ja|コンポーネントパレット]]の[[Standard tab/ja|Standardタブ]]の下にある。TPanelは他のコンポーネントの可視コンテナとして機能することができる。<br />
<br />
== 例 ==<br />
<br />
パネルを使用する方法の1つは、コントロールグループを表示および非表示にする場合である。<br />
個々のコントロールを表示または非表示にする代わりに、パネルとそのすべての子コントロールを1つのコマンドで非表示または表示することができる。<br />
この例では、次のコンポーネントが使用されている: [[TButton/ja]], [[TShape]]<br />
<br />
=== Create code ===<br />
<br />
*新しい空の[[Graphical User Interface|GUI]]アプリケーションを作成し、[[TForm|form]] Form1を作成します。<br />
* フォームのOnCreateイベントハンドラを作成するには、フォームをクリックし、オブジェクトインスペクタを使用して、イベントタブに移動し、OnCreateイベントを選択し、[...]ボタンをクリックするか、フォーム内のボタンをダブルクリックする。<br />
* 以下のコードを加える(足りない部分は補うこと):<br />
<br />
<syntaxhighlight lang="pascal"><br />
<br />
unit Unit1;<br />
<br />
{$mode objfpc}{$H+}<br />
<br />
interface<br />
<br />
uses<br />
Classes, SysUtils, Forms, Controls, Graphics, Dialogs, ExtCtrls, StdCtrls;<br />
<br />
type<br />
<br />
{ TForm1 }<br />
<br />
TForm1 = class(TForm)<br />
procedure FormCreate(Sender: TObject);<br />
private<br />
aPanel:TPanel;<br />
procedure aButtonClick(Sender: TObject);<br />
public<br />
<br />
end;<br />
<br />
var<br />
Form1: TForm1;<br />
<br />
implementation<br />
<br />
{$R *.lfm}<br />
<br />
{ TForm1 }<br />
<br />
procedure TForm1.FormCreate(Sender: TObject);<br />
var<br />
aButton:TButton;<br />
<br />
aShape1,aShape2:TShape;<br />
begin<br />
Caption :='Panel demo';<br />
aButton:=TButton.Create(Self);<br />
aButton.Parent:=Self;<br />
aButton.Caption:= 'Show/Hide';<br />
aPanel:=TPanel.Create(Self);<br />
aPanel.Parent:=Self;<br />
aPanel.Caption:='';<br />
aShape1:=TShape.Create(aPanel);<br />
aShape1.Parent:=aPanel;<br />
aShape1.Shape:=stStar;<br />
aShape1.Top := 5;<br />
aShape2:=TShape.Create(aPanel);<br />
aShape2.Parent:=aPanel;<br />
aShape2.Shape:=stStar;<br />
aShape2.Top := 5;<br />
aShape2.Left:=aShape1.Width+10;<br />
aPanel.Height:=aShape1.Height+10;<br />
aButton.Top:=aPanel.Height+10;<br />
aButton.OnClick:=@aButtonClick;<br />
Height := aButton.Top+aButton.Height+10;<br />
end;<br />
<br />
procedure TForm1.aButtonClick(Sender: TObject); //the event handler for the button<br />
begin<br />
if (Sender is TButton)<br />
then begin<br />
if aPanel.Visible then aPanel.Visible := false else aPanel.Visible := true;<br />
end;<br />
end;<br />
end.<br />
<br />
</syntaxhighlight><br />
==以下も参照のこと==<br />
* [[doc:lcl/extctrls/tpanel.html|TPanel doc]]<br />
* [[TBevel]]<br />
* [[TFrame]]<br />
* [[TFlowPanel]]<br />
<br />
{{LCL Components/ja}}</div>Aribenhttps://wiki.freepascal.org/TCheckGroup/jaTCheckGroup/ja2024-03-17T14:18:22Z<p>Ariben: /* 以下も参照のこと */</p>
<hr />
<div>{{TCheckGroup}}<br />
{{ Japanese Menu }}<br />
<br />
'''TCheckGroup'''[[image:tcheckgroup.png]]は、コンテナコンポーネント上で物理的におよび論理的にグループ化されたTCheckBoxアイテムのグループを含むコントロールである。<br />
<br />
<br />
<br />
TForm上でTCheckGroupを使用するには、単に[[Component Palette/ja|コンポーネントパレット]]の[[Standard tab/ja|Standardタブ]]でそれを選択し、フォーム上でクリックして配置する。<br />
<br />
===例===<br />
フォームの背景色を変更する。この色は、個々の色成分を加算して決定される:<br />
* 新しいアプリケーションを作成し、フォームにTCheckGroupを配置する。<br />
* オブジェクトインスペクタで、''CheckGroup1''の''Name''プロパティを''cgRed''に変更し、キャプションを''Red''に変更する。<br />
* ''cgRed''にチェックボックスを追加する。<br />
** オブジェクトインスペクタで、''cgRed''の''Items''プロパティを選択する。<br />
** [...]ボタンをクリックすると、文字列エディタが開く。<br />
** 1 2 4 8 16 32 64 128と入力し、''OK''ボタンをクリックしてエントリを完了する。<br />
* フォーム上の''cgRed''を右クリックし、「コピー」をクリックしてこのTCheckGroupをコピーする。<br />
* フォームを右クリックし、''Insert''をクリックして、名前が''cgRed1''のTCheckGroupが作成される。<br />
* ''cgRed1''の''Name''を''cgGreen''に変更し、''Caption''を''Green''に変更する。<br />
* TCheckGroupを挿入し、その名前を''cgBlue''に変更し、キャプションを''Blue''に変更する。<br />
* チェックボックスがクリックされるたびに、色が変わる。<br />
** オブジェクトインスペクタで、''cgRed''の''OnItemClick''イベントハンドラを作成するために、''OnItemClick''イベントの隣の [...] ボタンをクリックする。<br />
** ''cgGreen''と''cgBlue''についても同じイベントハンドラを選択するために、''OnItemClick''イベントの隣にあるComboBoxでそれぞれ''cgRedItemClick''を選択する。<br />
** ''cgGreen''と''cgBlue''に対しても同じイベントハンドラを選択するために、''OnItemClick''イベントの隣にあるコンボボックスでそれぞれ''cgRedItemClick''を選択する。<br />
** イベントハンドラに以下のコードを記述する:<br />
<br />
<syntaxhighlight lang=pascal><br />
procedure TForm1.cgRedItemClick(Sender: TObject; Index: integer);<br />
var<br />
i, c: Integer;<br />
begin<br />
c := $000000; // first the color is black<br />
for i:=0 to 7 do begin // test Items 0..7 of all Checkgroups<br />
if cgRed.Checked[i] then c := c + 1 shl i; // amount of red $000000..$0000FF<br />
if cgGreen.Checked[i] then c := c + 1 shl (i + 8); // amount of green $000000..$00FF00<br />
if cgBlue.Checked[i] then c := c + 1 shl (i + 16); // amount of blue $000000..$FF0000<br />
end;<br />
Color := c;<br />
end; <br />
</syntaxhighlight><br />
* プログラムを実行すると、以下のように見えるだろう: <br />
<br />
[[image:ExampleTCheckGroup.png]]<br />
<br />
==チェックボックスにアクセスする==<br />
<br />
TCheckGroup内の各アイテムにはCheckedプロパティがあり、それらをすべてチェック済みに設定するには、次のようにする。<br />
<br />
<syntaxhighlight lang=pascal>for i := 0 to MyCheckGroup.items.Count-1 do // 見つかったすべてのカテゴリを調べる<br />
MyCheckGroup.Checked[i] := true;<br />
</syntaxhighlight><br />
<br />
実行時にアイテムを追加するには、TCheckGroup.Itemsを使用する。これはTStringsリストである。新しいチェックボックスをセットに追加するには、単にMyCheckGroup.Items.add('CheckThis');を行う。同様に、すべてのアイテムを削除するには、リストをクリアする MyCheckGroup.Items.clear;<br />
<br />
==以下も参照のこと==<br />
<br />
* [[doc:lcl/extctrls/tcheckgroup.html|TCheckGroup doc]]<br />
* [[TCheckBox/ja]]<br />
* [[TGroupBox/ja]]<br />
<br />
{{LCL Components/ja}}</div>Aribenhttps://wiki.freepascal.org/TRadioGroup/jaTRadioGroup/ja2024-03-17T14:15:42Z<p>Ariben: /* See also */</p>
<hr />
<div>{{TRadioGroup}}<br />
<br />
{{ Japanese Menu }}<br />
<br />
TRadioGroup[[image:tradiogroup.png]]は、関連するが相互に排他的な[[TRadioButton/ja|TRadioButton]]のグループであり、ユーザーに対して選択肢の1つを選択する必要がある。それは、統合された[[TRadioButton/ja |TRadioButtons]]を持つ[[TGroupBox/ja | TGroupBox]]のようなものである。<br />
<br />
==使い方==<br />
[[TForm|Form]]でTRadioGroupを使用するには、単純に[[Component Palette/ja|Componentパレット]]の[[Standard tab/ja|Standardタブ]]でそれを選択し、フォームをクリックして配置します。<br />
<br />
===例===<br />
ジオメトリック図形は、TRadioGroupによってフォームにランダムに描画され、表示される。最初のRadioGroupは図形を決定し、2番目のRadioGroupは個数を決定する。<br />
* 新しいアプリケーションを作成し、フォームに2つのTRadioGroupを配置する。<br />
* オブジェクトインスペクタで、''RadioGroup1''の''Name''プロパティを''rgShape''に、''RadioGroup2''の''Name''プロパティを''rgCount''に変更する。<br />
* ''rgShape''の''Caption''を''Shape''に、''rgCount''の''Caption''を''Count''に変更する。<br />
** ''rgShape''のためのラジオボタンを追加する:<br />
** オブジェクトインスペクタで、''rgShape''の''Items''プロパティを選択する。<br />
** [...]ボタンをクリックすると、文字列エディタが開く。<br />
** それぞれ''Lines'', ''Rectangles'', ''Ellipses''と入力し、''OK''ボタンをクリックしてエントリを完了する。<br />
* ''rgCount''のためにも同様にラジオボタンを追加する(以下のように入力)1、5、10、20、50、100<br />
* ''rgShape''と''rgCount''の''ItemIndex''プロパティをそれぞれ''-1''から''0''に設定して、最初のRadioButtonを''currently selected''にする。<br />
* ''rgShape''をダブルクリックして、''rgShape''の''OnClick''イベントハンドラを作成する。<br />
* 同じイベントハンドラを''rgCount''にも使用する。<br />
** オブジェクトインスペクタで''rgCount''を選択する。<br />
** ここで、オブジェクトインスペクタで''Events''タブを選択してください。<br />
** ''OnClick''イベントに移動し、隣のコンボボックスで''rgShapeClick''を選択する。<br />
* ''rgShape''または''rgCount''がクリックされるたびに、フォームが再描画されるようにするために、次のコードをイベントハンドラに記述する:<br />
<syntaxhighlight lang="pascal"><br />
procedure TForm1.rgShapeClick(Sender: TObject);<br />
begin<br />
Repaint;<br />
end; <br />
</syntaxhighlight> <br />
* フォームが再描画されるたびに、図形を描画する必要がある。<br />
** オブジェクトインスペクタで ''Form1'' を選択する。<br />
** ''Events''タブを選択する。<br />
** ''OnPaint''イベントの横にある [...] ボタンをクリックする。<br />
** ハンドラが作成される。以下のコードを入力する:<br />
<syntaxhighlight lang="pascal"><br />
procedure TForm1.FormPaint(Sender: TObject);<br />
var<br />
i: Integer;<br />
begin<br />
if TryStrToInt(rgCount.Items[rgCount.ItemIndex], i) then<br />
for i:=1 to i do begin<br />
Canvas.Pen.Color:=Random($1000000);<br />
Canvas.Brush.Color:=Random($1000000);<br />
case rgShape.Items[rgShape.ItemIndex] of<br />
'Lines': Canvas.Line(Random(ClientWidth), Random(ClientHeight), Random(ClientWidth), Random(ClientHeight));<br />
'Rectangles': Canvas.Rectangle(Random(ClientWidth), Random(ClientHeight), Random(ClientWidth), Random(ClientHeight));<br />
'Ellipses': Canvas.Ellipse(Random(ClientWidth), Random(ClientHeight), Random(ClientWidth), Random(ClientHeight));<br />
end;<br />
end;<br />
end;<br />
</syntaxhighlight><br />
* プログラムを実行すると、以下のように見えるだろう:<br />
[[image:ExampleTRadioGroup.png]]<br />
<br />
==以下も参照のこと==<br />
* [[doc:lcl/extctrls/tradiogroup.html|TRadioGroup doc]]<br />
* [[TRadioButton/ja]]<br />
* [[TGroupBox/ja]]<br />
<br />
{{LCL Components/ja}}</div>Aribenhttps://wiki.freepascal.org/TGroupBox/jaTGroupBox/ja2024-03-17T14:07:29Z<p>Ariben: /* 例 */</p>
<hr />
<div>{{TGroupBox}}<br />
<br />
{{ Japanese Menu }}<br />
<br />
'''TGroupBox'''は、[[image:tgroupbox.png]]フォーム上で物理的および概念的に複数のオブジェクトをグループ化するためのコンテナである。GroupBox内のコントロールは、関連する機能や情報をグループ化して表示するのに役立つ。<br />
<br />
==使い方==<br />
フォーム上で[[doc:lcl/stdctrls/tgroupbox.html|TGroupBox]]を使用するには、単に[[Component Palette/ja|コンポーネントパレット]]の[[Standard tab/ja|Standardタブ]]からそれを選択し、フォーム上でクリックして配置する。GroupBoxは、関連するコントロールや情報を視覚的にグループ化するための便利なコンテナである。<br />
<br />
==例==<br />
* 新しいアプリケーションを作成し、フォームに2つのTGroupBoxを配置<br />
* GroupBox1には[[TButton/ja]]、''Button1''を、GroupBox2にはTButton、''Button2''を配置する。<br />
* フォームの外側に[[TRadioButton/ja]]を2つ配置する。<br />
* [[IDE_Window:_Object_Inspector/ja|オブジェクトインスペクタ]]で、RadioButton1のCaptionを''User''に、RadioButton2のCaptionを''Administrator''に変更する。<br />
* RadioButton2のChecked[[Property/ja|property]]を''[[True]]''に設定する。<br />
* RadioButton1をダブルクリックして、RadioButton1の''OnChange''[[Event handler|イベントハンドラ]]''を作成する。<br />
* このハンドラをRadioButton2のOnChangeイベントにも割り当てる。<br />
** オブジェクトインスペクタで、''RadioButton2''を選択する。<br />
** オブジェクトインスペクタに移動し''Events'' を選択する。<br />
** OnChangeイベントを選択し、隣接するコンボボックスで''RadioButton1Change''を選択する。<br />
* ラジオボタンのイベントハンドラで、''GroupBox2''をユーザーから非表示にする。<br />
** ソースエディタのRadioButtonのイベントハンドラに以下の行を記述する:<br />
<syntaxhighlight lang="Pascal"><br />
procedure TForm1.RadioButton1Change(Sender: TObject);<br />
begin<br />
GroupBox2.Visible:=Radiobutton2.Checked;<br />
end; <br />
</syntaxhighlight><br />
ボタンのイベントハンドラも追加し、以下のようなコードを追加する:<br />
<syntaxhighlight lang="Pascal"><br />
procedure TForm1.Button1Click(Sender: TObject);<br />
begin<br />
ShowMessage('User and administrator can click this button');<br />
end;<br />
procedure TForm1.Button2Click(Sender: TObject);<br />
begin<br />
ShowMessage('Only administrator can click this button');<br />
end; <br />
</syntaxhighlight><br />
* ボタンを押せる人を示す[[Dialog_Examples#ShowMessage|ShowMessage]]ダイアログに表示される。<br />
* 実行すると以下のように見える:<br />
<br />
[[image:ExampleTGroupBox1.png]] -> [[image:ExampleTGroupBox2.png]]<br />
<br />
==See also==<br />
* [[doc:lcl/stdctrls/tgroupbox.html|TGroupBox doc]]<br />
* [[TPairSplitter]]<br />
* [[TNotebook]]<br />
* [[TPageControl]]<br />
* [[TTabControl]]<br />
<br />
{{LCL Components/ja}}</div>Aribenhttps://wiki.freepascal.org/TScrollBar/jaTScrollBar/ja2024-03-17T14:05:30Z<p>Ariben: /* 例 */</p>
<hr />
<div>{{TScrollBar}}<br />
<br />
{{ Japanese Menu }}<br />
<br />
TScrollBarは、ユーザーがスライダーを移動させることで関連するコントロールのコンテンツをスクロールできるコントロールだ。<br />
<br />
==使い方==<br />
<br />
TScrollBarを使うには、[[Component Palette/ja]]の[[Standard tab/ja]]で選択し[[TForm|form]]に置く。<br />
<br />
==例==<br />
<br />
以下は、スクロールバーの位置に応じてフォーム上の画像を移動させる方法である:<br />
<br />
* フォームに2つのTScrollBarを配置する。<br />
* オブジェクトインスペクタで、最初のスクロールバーのプロパティを次のように変更する:「Name」を「sbVert」、「Kind」を「sbVertical」、「Align」を「alRight」へ。<br />
* オブジェクトインスペクタで、2番目のスクロールバーのプロパティを「Name」を「sbHori」、「Align」を「alBottom」に変更する。<br />
* フォームに[[TPaintBox]](追加のコンポーネントパレット)を追加し、「align」を「alClient」に設定する。<br />
* フォームに[[TImageList]](共通のコントロールコンポーネントパレット)を追加する。<br />
* 画像をImageListにアップロードする:<br />
** ImageList1を右クリックし、ポップアップメニューから''ImageList Editor...''を選択する。<br />
** ''Add''をクリックし、画像を選択する(できれば小さなアイコン16 x 16などを推奨する。例:Lazarus/images/icons/lazarus16x16)。<br />
** ''OK''で選択を完了します。<br />
* PaintBoxを選択し、オブジェクトインスペクタでイベントの下にある''OnPaint''イベントハンドラを作成し、次のコードを記述する:<br />
<br />
<syntaxhighlight lang=pascal><br />
procedure TForm1.PaintBox1Paint(Sender: TObject);<br />
begin<br />
ImageList1.Draw(<br />
Paintbox1.Canvas,<br />
sbHori.Position * (PaintBox1.ClientWidth - ImageList1.Width) div sbHori.Max,<br />
sbVert.Position * (Paintbox1.ClientHeight - ImageList1.Height) div sbVert.Max,<br />
0);<br />
end; <br />
</source><br />
* スクロールバーの位置の変更によってフォームを再描画するために、スクロールバーのイベントハンドラに''OnChange''を作成し、他のスクロールバーにも同様のイベントハンドラを呼び出す。<br />
<br />
<source><br />
procedure TForm1.sbVertChange(Sender: TObject);<br />
begin<br />
RePaint;<br />
end; <br />
</syntaxhighlight><br />
<br />
Your little program could look like:<br />
<br />
[[image:ScrollBarExample.png]]<br />
<br />
==以下も参照のこと==<br />
<br />
* [[doc:lcl/stdctrls/tscrollbar.html|TScrollBar doc]]<br />
* [[TTrackBar]]<br />
* [[TScrollBox]]<br />
<br />
{{LCL Components/ja}}</div>Aribenhttps://wiki.freepascal.org/TComboBox/jaTComboBox/ja2024-03-17T14:03:19Z<p>Ariben: /* csSimple */</p>
<hr />
<div>{{TComboBox}}<br />
<br />
{{ Japanese Menu }}<br />
<br />
A '''TComboBox''' [[image:tcombobox.png]] is a combination of an edit box and a (drop-down) list allowing one of several options to be chosen.<br />
<br />
=使い方=<br />
<br />
TComboBoxは、エディットボックスと(ドロップダウン)リストの組み合わせで、いくつかのオプションの中から一つを選択できるようにするものである。<br />
<br />
フォーム上で[[doc:lcl/stdctrls/tcombobox.html|TComboBox]]を使用するには、[[Component Palette/ja]]の[[Standard tab/ja]]タブからそれを選択し、フォーム上でクリックして配置するだけである。<br />
<br />
ComboBox内に保存された文字列は、[[TStringList-TStrings Tutorial|TStrings]]型のプロパティ''Items''に保存される。そのため、[[TStringList-TStrings Tutorial|TStringList]]やその親クラスであるTStringsで行うように、ComboBox内の文字列を割り当てたり削除したりすることができる。<br />
<br />
フォーム''Form1''上のcombobox ''ComboBox1''を使用するいくつかの例を紹介する:<br />
<br />
==コンボボックスを埋める==<br />
<br />
===オブジェクトインスペクタによって===<br />
<br />
* フォーム上のComboBoxをクリックで選択する。<br />
* オブジェクトインスペクタでプロパティタブに移動し、プロパティ''Items''を選択する。<br />
* 3つのドットがあるボタンをクリックする。すると、文字列エディタが開く。<br />
* テキストを入力し、''OK''で作業を確定する。<br />
<br />
===フォームを作るときにコードから===<br />
* フォームのOnCreateイベントハンドラを作成するには、まずフォームをクリックし、オブジェクトインスペクタでイベントタブを選択する。''OnCreate''イベントを見つけ、[...]ボタンをクリックするか、フォーム内のどこかをダブルクリックする。<br />
* ソースエディタに移動したら、望む選択テキストを挿入することになる。例えば、以下のように記述することになる:<br />
<br />
<syntaxhighlight lang=pascal><br />
procedure TForm1.FormCreate(Sender: TObject); <br />
begin<br />
ComboBox1.Items.Clear; //存在しているすべての選択を解除<br />
ComboBox1.Items.Add('Red'); //選択を加える<br />
ComboBox1.Items.Add('Green');<br />
ComboBox1.Items.Add('Blue');<br />
ComboBox1.Items.Add('Random Color'); <br />
end;<br />
</syntaxhighlight><br />
<br />
==選択したときに何かを起こさせる==<br />
<br />
すべてのコンポーネントと同様に、TComboBoxもさまざまな[[Event_order|イベント]]を提供しており、これらはユーザーがコンボボックスを使用したときに呼び出される。ComboBoxでの選択の変更に応答するには、''OnChange''イベントを使用できる:<br />
<br />
*フォーム上のComboBoxをダブルクリックするか、オブジェクトインスペクタで''OnChange''イベントを選択し、[...]ボタンをクリックする。<br />
*イベントハンドラが作成される。ここで、必要なソースコードを挿入できる。私たちの例では、フォームの背景色を変更したいと考えている:<br />
<br />
<syntaxhighlight lang=pascal><br />
procedure TForm1.ComboBox1Change(Sender: TObject);<br />
begin<br />
case ComboBox1.ItemIndex of //どれが(どのアイテムが)現在選択されているか<br />
0: Color:=clRed;<br />
1: Color:=clGreen;<br />
2: Color:=clBlue;<br />
3: Color:=Random($1000000);<br />
end;<br />
end;<br />
</syntaxhighlight><br />
<br />
* アプリケーションを起動すると、によりフォームの背景色が変更される。<br />
<br />
==イベント==<br />
<br />
''OnGetItems''イベントは、ウィジェットセットのアイテムリストを作成できる場合に呼び出される。そのため、コンボボックスのボタンが押されたときにトリガーされる。<br />
<br />
==所有者によって描かれたコンボボックス==<br />
一般的には、ユーザーが設定で選択したテーマをComboBoxに表示させる方が有利だ。しかし、場合によっては(例えば、カラフルな表面のゲームをプログラムする場合など)、この標準から逸脱し、独自の選択に基づいて描画することもできる。その方法は次の通りである:<br />
<br />
{{Note|'''ComboBoxDrawItemのパラメータ :'''<br><br><br />
'''Control:'''<br> もし複数のコントロール(例えば、複数のコンボボックス)がこのイベントハンドルにアクセスするなら、どのコントロールがイベントを引き起こしているか知ることになる。この例では'''<code>ComboBox1.Canvas.FillRect(ARect)</code>'''の代わりに、と書ける'''<code>TComboBox(Control).Canvas.FillRect(ARect)</code>'''。しかし、それがTComboBoxか否か、事前に確認すべきである:<br />
<br />
<syntaxhighlight lang=pascal><br />
if Control is TComboBox then<br />
TComboBox(Control).Canvas.FillRect(ARect); <br />
</syntaxhighlight><br />
<br />
'''Index:''' <br />
アイテムの場所を特定する。そこで文字列、'''<code><ComboBox>.Items[Index]</code>'''.にアクセスできる<br><br />
'''ARect:'''<br />
四角形を述べる。それは背景を描くときに必要である。<br><br />
'''State:'''<br />
アイテムの状態、通常、フォーカスされている、選択されているなど<br />
}}<br />
<br />
===塗りつぶされた四角形を描く===<br />
<br />
* フォームを作成する際に、[[TComboBox/ja#フォームを作るときにコードから|フォームを作るときにコードから]]の例をを変更することができる。<br />
* オブジェクトインスペクタで、ComboBox1のプロパティStyleをcsOwnerDrawFixedに変更する。<br />
* オブジェクトインスペクタで、イベントOnDrawItemのイベントハンドラを作成するために、[...]ボタンをクリックする。<br />
* 次のコードをハンドラに追加する:<br />
<br />
<syntaxhighlight lang=pascal><br />
procedure TForm1.ComboBox1DrawItem(Control: TWinControl; Index: Integer;<br />
ARect: TRect; State: TOwnerDrawState);<br />
var<br />
ltRect: TRect;<br />
<br />
procedure FillColorfulRect(aCanvas: TCanvas; myRect: TRect); //任意の色で塗る<br />
// Fills the rectangle with random colours<br />
var<br />
y: Integer;<br />
begin<br />
for y:=myRect.Top to myRect.Bottom - 1 do begin<br />
aCanvas.Pen.Color:=Random($1000000);<br />
aCanvas.Line(myRect.Left, y, myRect.Right, y);<br />
end;<br />
end;<br />
<br />
begin<br />
ComboBox1.Canvas.FillRect(ARect); //最初の通常の背景<br />
ComboBox1.Canvas.TextRect(ARect, 22, ARect.Top, ComboBox1.Items[Index]); //アイテムテキストを塗る<br />
<br />
ltRect.Left := ARect.Left + 2; //四角形のための色<br />
ltRect.Right := ARect.Left + 20;<br />
ltRect.Top := ARect.Top + 1;<br />
ltRect.Bottom := ARect.Bottom - 1;<br />
<br />
ComboBox1.Canvas.Pen.Color:=clBlack;<br />
ComboBox1.Canvas.Rectangle(ltRect); //縁を描く<br />
<br />
if InflateRect(ltRect, -1, -1) then //1ピクセル四角形の大きさを変更する<br />
if Index = 3 then<br />
FillColorfulRect(ComboBox1.Canvas, ltRect) //任意の色を塗る<br />
else begin<br />
case Index of<br />
0: ComboBox1.Canvas.Brush.Color := clRed;<br />
1: ComboBox1.Canvas.Brush.Color := clGreen;<br />
2: ComboBox1.Canvas.Brush.Color := clBlue;<br />
end;<br />
ComboBox1.Canvas.FillRect(ltRect); //選択に応じて色を塗る<br />
end;<br />
end;<br />
</syntaxhighlight><br />
<br />
* このように見えるだろう:<br />
<br />
[[image:ComboBoxBsp1.png]] -> [[image:ComboBoxBsp2.png]]<br />
<br />
===前に画像を置く===<br />
<br />
この例では、TImageListにいくつかの画像を読み込み、それらをコンボボックスのアイテムの前に描画する。これは、一般的にできることを示すシンプルな例だ。この例では、対応する画像が存在するかどうかなどの詳細を明示的に実行しない。必要に応じてそれらは行われるべきである。<br />
<br />
* フォームを作成する際に、コードで例と同様のアプリケーションを作成します。<br />
* オブジェクトインスペクタで、ComboBox1のプロパティStyleを''csOwnerDrawFixed''に変更する。<br />
* コンポーネントパレットのCommon controlsからTImageListを追加する。<br />
* ImageList1の高さと幅は16ピクセルに設定されている。これを許可する。画像をコンボボックスにきれいに収めるために、ComboBox1のプロパティItemHeightをオブジェクトインスペクタで18に設定する。<br />
* ImageListに4つの画像を追加する:<br />
** ImageList1をダブルクリックするか、''ImageList1''を左クリックして''ImageList Editor''を選択する。<br />
** [Add]をクリックして画像を選択します(<Lazarusディレクトリ>/images/...にはさまざまな16x16pxサイズの画像やアイコンがある)。<br />
** 4つの画像を追加したら、[OK]で作業を確定する。<br />
* オブジェクトインスペクタで、イベントOnDrawItemのイベントハンドラを作成します。[...]ボタンをクリックする。<br />
* 次のコードをハンドラに追加する:<br />
<br />
<syntaxhighlight lang=pascal><br />
procedure TForm1.ComboBox1DrawItem(Control: TWinControl; Index: Integer;<br />
ARect: TRect; State: TOwnerDrawState);<br />
begin<br />
ComboBox1.Canvas.FillRect(ARect); //はじめ通常の背景で塗る<br />
ComboBox1.Canvas.TextRect(ARect, 20, ARect.Top, ComboBox1.Items[Index]); //アイテムテキストを塗る<br />
ImageList1.Draw(ComboBox1.Canvas, ARect.Left + 1, ARect.Top + 1, Index); //キャンバスのインデクスに従って画像を描く<br />
end;<br />
</syntaxhighlight><br />
<br />
* このように見えるだろう:<br />
<br />
[[image:ComboBoxBsp1.png]] -> [[image:ComboBoxBsp3.png]]<br />
<br />
==スタイル==<br />
===csSimple===<br />
'''csSimple'''は、下にリストボックスがある単純な編集ボックスを表す。十分な高さが割り当てられている場合にのみリストボックスが表示される。デフォルトでは、編集ボックスのみが表示される高さに設定されている。<br />
<br />
リストボックスを表示するためのドロップダウンアイコンがある。キーボード(矢印キーを)使用するか、コントロールがアイテムリストを表示するのに十分な高さがある場合にアイテムをクリックしてアイテムを変更できる。<br />
<br />
'''csSimple'''スタイルはWindowsに固有のものです。非Windowsのウィジェットセットは、おそらく実装されておらず、代わりに'''csDropDown'''にフォールバックするだろう。<br />
<br />
以下は、異なるウィジェットセットで(自動サイズ調整されていない)csSimple ComboBoxの例だ(Lazarus 2.0.8現在):<br />
<br />
<gallery><br />
Image:cssimple_win.png|Win32<br />
Image:cssimple_gtk2.png|Gtk2<br />
</gallery><br />
<br />
=提案されている特徴=<br />
==読み取り専用==<br />
<br />
ReadOnlyプロパティは2017年以来非推奨となり、現時点で削除されている。<br />
<br />
ただし、ReadOnlyプロパティをTEditのreadonly機能のミラーとして復活させることは可能である。<br />
<br />
ComboBoxの複雑さは、それがListBoxとEditの両方の機能を持っていることだ(ただし、いずれの派生クラスでもない)。<br />
ComboBoxは選択を変更する手段を提供しており(TEditと同様に)、編集ボックスを読み取り専用にすることも有益かもしれない(これはcsDropDownListとは異なる。csDropDownListは通常、ドロップダウンをボタンとして実装する)。<br />
<br />
ReadOnlyプロパティが期待どおり機能する方法は次のとおりである:<br />
<br />
* 任意のComboBoxスタイルで利用可能であるはずだ。<br />
* それはComboBoxの選択されたスタイルに影響を与えず、また影響されるべきではない(以前のReadOnlyの実装とは異なる)。<br />
* trueに設定された場合:<br />
** 編集ボックス(ウィジェットセットのComboBoxスタイルでサポートされている場合)は、TEditと同様に読み取り専用になる。つまり、テキストの編集、貼り付け、テキストのドラッグなどのテキスト入力アクションでコンテンツを変更できない。<br />
* ただし、コンボボックスの値は、ドロップダウンから別のアイテムを選択することで変更できます。これはマウスを使用するか、対応するキーの組み合わせ(上下矢印など)を使用して行える。<br />
<br />
==テキストヒント==<br />
<br />
ComboBoxがTEditの特性を持っているため、値が空の場合にTextHintをcomboBoxに設定することができるはずだ。<br />
<br />
以下のように、TextHintプロパティを導入する。<br />
<br />
* TextHintプロパティはTEditと同様に機能する。<br />
* コンボボックスのテキスト値が空の場合、TextHintが表示される(現在のウィジェットセットのテーマに適用可能な色とフォントスタイルで表示される)。<br />
<br />
= 以下も参照のこと =<br />
<br />
* [[doc:lcl/stdctrls/tcombobox.html|TComboBox]]<br />
* [[TEdit]]<br />
* [[TListBox]]<br />
* [[TDBComboBox]]<br />
* [[TDBLookupComboBox]]<br />
<br />
{{LCL Components/ja}}</div>Aribenhttps://wiki.freepascal.org/TListBox/jaTListBox/ja2024-03-17T14:00:54Z<p>Ariben: /* 所有者によって書かれたリストボックス */</p>
<hr />
<div>{{TListBox}}<br />
<br />
{{ Japanese Menu }}<br />
<br />
'''TListBox''' [[image:tlistbox.png]]は、ユーザーが1つ選択する必要がある(スクロール可能な)短い文字列のリストを表示するコンポーネントである。[[Component Palette/ja|コンポーネントパレット]]の[[Standard tab/ja|Standardタブ]]で利用できる。<br />
<br />
TListBoxにある[[String|strings]]は[[TStrings]]型である''Items''プロパティに格納されている。そのため、[[TStringList]]またはその親である[[TStringList-TStrings Tutorial|TStrings]]にあるように、リストボックス内に文字列を割り当て、もしくは取り除くことができる。<br />
<br />
これは''Form1''のTListBox ''ListBox1''の使い方のいくつかの例である:<br />
<br />
==リストボックスを埋める==<br />
===オブジェクトインスペクタにより===<br />
* フォーム上のListBoxを1回のクリックで選択する。<br />
* PropertiesタブでObject Inspectorに移動し、''Items''というプロパティを選択する。<br />
* 3つの点があるボタンをクリックする。String Editorが開く。<br />
* テキストを入力し、''OK''で作業を確認する。<br />
<br />
===ボタンクリックでコードにより===<br />
フォームに、名前が''btnFill''でキャプションが''fill ListBox''となる[[TButton]]を追加する。そのボタンの''OnClick''イベントハンドラには、以下のコードを記述する:<br />
<syntaxhighlight lang=pascal><br />
procedure TForm1.btnFillClick(Sender: TObject);<br />
begin<br />
ListBox1.Items.Clear; //Delete all existing strings<br />
ListBox1.Items.Add('First line');<br />
ListBox1.Items.Add('Line with random number '+IntToStr(Random(100)));<br />
ListBox1.Items.Add('Third line');<br />
ListBox1.Items.Add('Even a random number '+IntToStr(Random(100)));<br />
end;<br />
</syntaxhighlight><br />
<br />
==StringListの割り当て==<br />
フォームに、名前が''btnFill''でキャプションが''fill ListBox''となる[[TButton/ja]]を追加する。そのボタンの''OnClick''イベントハンドラには、以下のコードを記述する:<br />
<syntaxhighlight lang=pascal><br />
procedure TForm1.btnFillClick(Sender: TObject);<br />
var<br />
myStringList: TStringList;<br />
begin<br />
myStringList:=TStringList.Create; //StringListを作る<br />
myStringList.Add('This is the first line.'); //新しい行を追加する<br />
myStringList.Add('This is the second first line.');<br />
myStringList.Add('This is the third line.');<br />
myStringList.Add('etc.');<br />
ListBox1.Items.Assign(myStringList); //ListBox1にStringListの内容を割り当てる<br />
myStringList.Free; //メモリからStringListを解放する<br />
end;<br />
</syntaxhighlight><br />
<br />
==文字列を追加する==<br />
* [[TListBox/ja#ボタンクリックでコードにより|ボタンクリックでコードにより]]埋める、を拡張し、TEditと名前が''btnAdd''でキャプションが''add string''のTButtonを追加し、''Edit1''のTextプロパティを"" - 空の文字列に変更する。<br />
* ボタンのイベントハンドラ''OnClick''に以下のコードを書く:<br />
<syntaxhighlight lang=pascal><br />
procedure TForm1.btnAddClick(Sender: TObject);<br />
begin<br />
ListBox1.Items.Add(Edit1.Text);<br />
Edit1.Text:='';<br />
end; <br />
</syntaxhighlight><br />
<br />
==文字列を削除する==<br />
<br />
デフォルトでは、ListBoxで1行のみを選択できるように設定されている。ListBoxで複数の行を選択する場合は、''MultiSelect''プロパティを''True''に設定する必要がある。<br />
<br />
===ItemIndexで===<br />
<br />
* [[TListBox/ja#文字列を追加する|文字列を追加する]]を拡張し"btnDel"の名前の[[TButton/ja|TButton]]、そのキャプションを"delete string"とする。<br />
* ボタンの''OnClick''イベントハンドラに以下のコードを書く:<br />
<syntaxhighlight lang=pascal><br />
procedure TForm1.btnDelClick(Sender: TObject);<br />
begin<br />
if ListBox1.ItemIndex > -1 then //リストボックスの文字列が選択されたときのみ削除<br />
ListBox1.Items.Delete(ListBox1.ItemIndex);<br />
end; <br />
</syntaxhighlight><br />
<br />
===all selected strings===<br />
* [[TListBox/ja#文字列を追加する|文字列を追加する]]を拡張し"btnDel"の名前の[[TButton/ja|TButton]]、そのキャプションを"delete string"とする。<br />
* ボタンの''OnClick''イベントハンドラに以下のコードを書く:<br />
<syntaxhighlight lang=pascal><br />
procedure TForm1.btnDelClick(Sender: TObject);<br />
var<br />
i: Integer;<br />
begin<br />
if ListBox1.SelCount > 0 then //リストボックスの少なくとも1つの文字列が選択されたときのみ削除する<br />
for i:=ListBox1.Items.Count - 1 downto 0 do //すべてのアイテムをイテレート<br />
if ListBox1.Selected[i] then //もし選択されたら...<br />
ListBox1.Items.Delete(i); //...そのアイテム(文字列)を削除<br />
end;<br />
</syntaxhighlight><br />
<br />
==所有者によって書かれたリストボックス==<br />
一般的には、リストボックスをユーザーによって設定された[http://en.wikipedia.org/wiki/Skin_%28computing%29 テーマ]に従わせることが有効である。ある場合(例えば、色彩の多い表面を持つゲームをプログラムするため)ではこの標準から逸脱し、自身の選択に従ってコントロールを描くことができる。<br />
これを、<br />
* 上の例を変更するか、TListBox ''ListBox1''をもつ新しいアプリケーションを作る<br />
* オブジェクトインスペクタで''ListBox1''のプロパティ、''Style''を''lbOwnerDrawFixed''へ変更する。<br />
* オブジェクトインスペクタのイベントタブで[...]ボタンをクリックすることで、''OnDrawItem''イベントに対するイベントハンドラを作る。<br />
* イベントハンドラに以下のコードを加える:<br />
<syntaxhighlight lang=pascal><br />
procedure TForm1.ListBox1DrawItem(Control: TWinControl; Index: Integer;<br />
ARect: TRect; State: TOwnerDrawState);<br />
var<br />
aColor: TColor; //背景色<br />
begin<br />
if (Index mod 2 = 0) //インデクスがどのアイテムか知らせる<br />
then aColor:=$FFFFFF //背景色として1秒ごとにアイテムが白になる<br />
else aColor:=$EEEEFF; //背景色として1秒ごとにアイテムが桃になる<br />
if odSelected in State then aColor:=$0000FF; //もしアイテムが選択されると、背景色は赤となる。<br />
ListBox1.Canvas.Brush.Color:=aColor; //背景色を設定する<br />
ListBox1.Canvas.FillRect(ARect); //塗りつぶされた四角形を描く<br />
<br />
ListBox1.Canvas.Font.Bold:=True; //フォントを「太字」に設定する<br />
ListBox1.Canvas.TextRect(ARect, 2, ARect.Top+2, ListBox1.Items[Index]); //アイテムテキストを描く<br />
end;<br />
</syntaxhighlight><br />
と書くことができる。<br />
{{Note|'''リストボックスアイテムのパラメータ:'''<br><br>'''Control:'''<br>複数のコントロール(例えば、複数のリストボックス)がこのハンドルにアクセスする場合、どれがこのイベントを発生させたかわかる。それがTListBoxかどうか、'''<syntaxhighlight lang=pascal>ListBox1.Canvas.FillRect(ARect)</syntaxhighlight>'''また、'''<syntaxhighlight lang=pascal>TListBox(Control).Canvas.FillRect(ARect)</syntaxhighlight>'''の代わりに、事前に問い合わせるべきであり<syntaxhighlight lang=pascal>if Control is TListBox then<br />
TListBox(Control).Canvas.FillRect(ARect);<br />
</syntaxhighlight>と書くことができる。<br />
'''Index:''' <br />
アクセスできるように、アイテムの場所を特定する<br />
'''<syntaxhighlight lang=pascal><ListBox>.Items[Index]</syntaxhighlight>'''.<br><br />
'''ARect:'''<br />
背景を描くために必要な、四角形を描写する。<br><br />
'''State:'''<br />
通常、フォーカスされた、選択されたなどアイテムの状態。<br />
}}<br />
* 例では以下のように見えるはずである:<br />
[[image:ListBoxBsp1.png]] -> [[image:ListBoxBsp2.png]]<br />
<br />
==See also==<br />
* [[doc:lcl/stdctrls/tlistbox.html|TListBox doc]]<br />
* [[TDBListBox]]<br />
* [[ListBox with separators]]<br />
* [http://forum.codecall.net/topic/73705-the-basic-working-with-tlistbox/ tutorial about TListBox]<br />
<br />
{{LCL Components/ja}}</div>Aribenhttps://wiki.freepascal.org/TRadioButton/jaTRadioButton/ja2024-03-17T13:58:29Z<p>Ariben: /* イベントの使い方 */</p>
<hr />
<div>{{TRadioButton}}<br />
<br />
{{ Japanese Menu }}<br />
<br />
<br />
'''TRadioButton''' [[image:tradiobutton.png]]は相互排他的 - もし1つのボタンが選択されると、同じグループの他のものが選択できない - に他のラジオボタンともに機能するボタン選択を現すコンポーネントである。TRadioButtonは[[Component Palette/ja|コンポーネントパレット]]の[[Standard tab/ja|Standardタブ]]で選択できる。<br />
<br />
[[TForm|Form]]でTRadioButtonを使うには、単にコンポーネントパレット''Standard''から、選んでフォーム上でクリックし、配置する。<br><br />
ラジオボタンは何でも選択可能なので、通常は単一のラジオボタンを用いることは意味をなさない。そのため、個々のラジオボタンの代わりに[[TRadioGroup]]を用いることもできる。<br />
<br />
ソースコードのどこからでも、クエリ、'''<code>Status := <RadioButton>.Checked;</code>'''により、有効か、無効かラジオボタンの状態を取得できる。通常の[[Boolean|ブール値]]として''Checked''を使うことができる。このため、割り当て、'''<code><RadioButton>.Checked := True;</code>'''が可能である。<br />
<br />
===簡単な例===<br />
<br />
* 新しいアプリケーションを作り、3つのラジオボタンを配置する。<br />
* オブジェクトインスペクタタブのプロパティで名前を''RadioButton1...3''から、''rbRed''、''rbGreen''、''rbBlue''に変更する。<br />
* 同様にそれらのラジオボタンのキャプションを''Red''、''Green''、''Blue''に変更する。<br />
* フォームに[[TButton]]を加え、そのキャプションを''Draw new''、その名前を''btnPaint''に変更する。<br />
* ''OnClick''をオブジェクトインスペクタで選択し、[...]をクリックし、TButtonに対し''OnClick''イベントハンドラを作る。<br />
* 以下のコードを加える:<br />
<br />
<syntaxhighlight lang=pascal><br />
procedure TForm1.btnPaintClick(Sender: TObject);<br />
begin<br />
if rbRed.Checked then Color:=clRed;<br />
if rbGreen.Checked then Color:=clLime;<br />
if rbBlue.Checked then Color:=clBlue;<br />
end;<br />
</syntaxhighlight><br />
* アプリケーションでは、以下のように見えるはずである:<br />
<br />
[[image:RadioButtonExample1.png]] -> [[image:RadioButtonExample2.png]]<br />
<br />
===イベントの使い方===<br />
<br />
上の例との相違は、ボタンのクリックではなく、すでにラジオボタンの1つが選択された状態で再描画することである。<br />
<br />
ソースコードより、ボタンとその''OnClick''イベントハンドラを削除することにより、前の例を変更できる。新しい例もまた、簡単に作れる:<br />
* 新しいアプリケーションを作り、フォームに3つのラジオボタンを配置する。<br />
* オブジェクトインスペクタプロパティタブで、その名前を''RadioButton1...3''から''rbRed''、''rbGreen''、''rbBlue''へ変更する。<br />
* 同様にラジオボタンのキャプションも''Red''、''Green''、''Blue''に変更する。<br />
* ここでラジオボタンに''OnChange''イベントハンドラを作る。すべてのラジオボタンに対して、オブジェクトインスペクタイベントタブで''OnChange''イベントを選択し[...]をクリックするか、そのうえでダブルクリックする。<br />
* クリックされたラジオボタンに応じて、ラジオボタンの''OnChange''イベントハンドラにフォームの色を変更させるため:<br />
<br />
<syntaxhighlight lang=pascal><br />
procedure TForm1.rbRedChange(Sender: TObject);<br />
begin<br />
Self.Color:=clRed; //「Self」で、メソッドが存在するオブジェクトを選択する(メソッド:rbRedChange/オブジェクト:Form1)<br />
end;<br />
<br />
procedure TForm1.rbGreenChange(Sender: TObject);<br />
begin<br />
Form1.Color:=clLime; //直接オブジェクト''Form1''を選択できるが、お粗末である。 <br />
//なぜなら、クラス「Form1」の他のオブジェクトが生成されてないからだ<br />
end; //訳注: clLimeとなっているが本文中ではclGreenである<br />
<br />
procedure TForm1.rbBlueChange(Sender: TObject);<br />
begin<br />
Color:=clBlue; //もしくは「Self」を取り除く、そしてコンパイラは自動的に<br />
end; //それ自身のオブジェクトを探し出すだろう<br />
</syntaxhighlight><br />
<br />
* アプリケーションを実行すると、このように見えるはずだ:<br />
<br />
[[image:RadioButtonExample3.png]] -> [[image:RadioButtonExample4.png]]<br />
<br />
===グルーピング===<br />
<br />
ラジオボタンをフォームに追加すると、そのフォームが親(ラジオボタンを含むコントロール)となる。ラジオボタンを選択するたびに(クリックまたはコードによって)、各設定で'''<code><RadioButton>.Checked:=True;</code>'''が行われると、同じ親を持つ異なるラジオボタンが選択されているかどうかを確認し、もしそうであれば、そのプロパティ''Checked''がFalseに変更される。<br><br />
もし複数のラジオボタンをフォームで使い、異なる、独立した選択を提供するように設計したいのであれば、ラジオボタンをグループ化しなければならない。このため完成したコンポーネント[[TRadioGroup]]がある、または(例えば、[[TPanel]]、[[TGroupBox]]、[[TNotebook]]、[[TPageControl]]などで)コントロールにまとめることになる。<br><br />
<br />
以下の例はどのようにラジオボタンをまとめることができるかを示している:<br />
<br />
[[TRadioButton/ja#簡単な例|簡単な例]]を変更するか、新しいアプリケーションを作り:<br />
* 初めにStandardコンポーネントパレットの[[TGroupBox]]をフォームに配置する必要がある。<br />
* その名前を''gbColor''へ、そのキャプションを''Color''に変更する。<br />
* ここで、このグループボックスを''rbRed''、''rbGreen''、''rbBlue''へサブクラス化する:<br />
** 変更したプロジェクトで、引き続きオブジェクトインスペクタにあるラジオボタンを''gbColor''へ向けて、ドラッグアンドドロップによりで移動する。<br />
** 新しいプロジェクトで、GroupBoxで挿入するためにクリックすることにより、それらの後に3つのラジオボタンを挿入し、名前を''rbRed''、''rbGreen''、''rbBlue''へ、キャプションを''Red''、''Green''、''Blue''へ変更する。<br />
** <br />
* そして、2番目のTGroupBoxをフォームに配置し、''gbBrightness''、とキャプションを''Brightness''名づける。<br />
* このグループボックスはまた3つのラジオボタンをもち、名前を''rbBrightDark''、''rbBrightMedDark''、''rbBrightBright''、そしてキャプションを''Dark''、''MediumDark''、''Bright''と名づける。<br />
* 新しいアプリケーションを作った場合、フォームにボタンを追加し''btnPaint''、キャプション''Draw new''と名づけなければならない。<br />
* ''btnPaint''の''OnClick''イベントハンドラのコードを以下に変更する:<br />
<br />
<syntaxhighlight lang=pascal><br />
procedure TForm1.btnPaintClick(Sender: TObject);<br />
begin<br />
if rbRed.Checked then Color:=Brightness or clRed;<br />
if rbGreen.Checked then Color:=Brightness or clLime;<br />
if rbBlue.Checked then Color:=Brightness or clBlue; <br />
end;<br />
</syntaxhighlight><br />
<br />
* そして、さらにTForm1の''private''節にコード'''<code>function Brightness: TColor;</code>'''を書き、[CTRL] + [Shift] + [c] (コード補完)を押す。関数が生成される。以下のコードを入力する:<br />
<br />
<syntaxhighlight lang=pascal><br />
function TForm1.Brightness: TColor;<br />
begin<br />
Result:=0;<br />
if rbBrightMedDark.Checked then Result:=$888888;<br />
if rbBrightBright.Checked then Result:=$DDDDDD;<br />
end;<br />
</syntaxhighlight><br />
<br />
* アプリケーションを実行すると、グループ化された独立したラジオボタンを用いることができ、以下のように見えるだろう:<br />
<br />
[[image:RadioButtonExample5.png]] -> [[image:RadioButtonExample6.png]]<br />
<br />
==以下も参照のこと==<br />
<br />
* [[doc:lcl/stdctrls/tradiobutton.html|TRadioButton doc]]<br />
* [[TRadioGroup]] - Usage of RadioGroups<br><br />
* [[TToggleBox]] - Usage of Toggleboxes<br><br />
* [[TCheckBox]] - Usage of CheckBoxes<br><br />
<br />
{{LCL Components/ja}}</div>Aribenhttps://wiki.freepascal.org/TCheckBox/jaTCheckBox/ja2024-03-17T13:51:02Z<p>Ariben: </p>
<hr />
<div>{{TCheckBox}}<br />
<br />
{{ Japanese Menu }}<br />
<br />
<br />
A '''TCheckBox''' [[image:tcheckbox.png]]はチェックマークを含むボックスを持つラベルを提供するコンポーネントである。TCheckboxがチェックされる(☑)とcheckedプロパティが[[True]] となり、さもなくば [[False]]である。<br />
これは[[Component Palette/ja|コンポーネントパレット]]の[[Standard tab/ja|Standardタブ]]から得られる。<br />
もし、プロパティAllowGrayedがFalse(デフォルト)に設定されると、チェックボックスはただ2つの状態(Stateプロパティ): cbCheckedとcbUncheckedのを持つ。もし、AllowGrayedがTrueに設定されると、チェックボックスは3つの状態: cbChecked、cbUnchecked、cbGrayedを持つ。<br />
<br />
[[image:TCheckBox-milk-sugar.png]]<br />
<br />
==使い方==<br />
フォームで[[doc:lcl/stdctrls/tcheckbox.html|TCheckBox]]を使うには<br />
# StandardタブのTCheckBoxコントロールをクリックする。<br />
# フォームをクリックするとそこにチェックボックスが配置される。<br />
# オブジェクトインスペクタに移動し、'''Properties'''タブの'''Name'''プロパティで何かふさわしいものに名前を変える。<br />
# '''Checked'''プロパティでは、もしデフォルトの状態がチェックされてないと、FalseからTrueに切り替えるときに値の上でダブルクリックする。<br />
# チェックボックスの右側にラベルが現れ、通常'''Checkbox1'''といったような名前が付けられている。表示されているラベルを変更するには'''Caption'''プロパティに移動し、望むものに変え、エンターを押す。<br />
# 何かの都合でチェックボックスの左側にラベルを現したいときは、'''BidiMode'''プロパティに移動し、この値を、'''bdLeftToRight'''に変更する。これを通常の表示に戻したいときは'''bdRightToLeft'''に変更する。<br />
# もしチェックボックスが単に値を保持しているのならば、完了である。もしそれがクリックされたときに何かをさせたい場合には、イベントを加えなければならない。そのためには'''Events'''タブをクリックし、'''OnClick'''プロパティをクリックし、[...]のボタンをクリックする。それでコードウインドウに移動し、OnClickイベントハンドラが作られるだろう。そして、このイベントが発生したら実行されるべきコードを入力することができる。<br />
# チェックボックスの値をコードの中で変更するには、それぞれチェックボックスがチェックされているか否かを表示するため'''checked'''プロパティの値を、{{TF}}に設定する。<br />
<br />
== 以下も参照のこと==<br />
* [[doc:lcl/stdctrls/tcheckbox.html|TCheckBox doc]]<br />
* [[TCheckGroup]]<br />
* [[TCheckListBox]]<br />
* [[TLabel/ja|TLabel]]<br />
<br />
{{LCL Components/ja}}</div>Aribenhttps://wiki.freepascal.org/TToggleBox/jaTToggleBox/ja2024-03-17T13:48:39Z<p>Ariben: /* 以下も参照のこと */</p>
<hr />
<div>{{TToggleBox}}<br />
<br />
{{ Japanese Menu }}<br />
<br />
<br />
'''TToggleBox''' [[image:ttogglebox.png]]はシングルクリックで有効もしくは、無効とされる2つの状態を保持するラベルのあるボタンである。これは[[Component Palette/ja|コンポーネントパレット]]の[[Standard tab/ja|Standardタブ]]で利用できる。<br />
<br />
[[Source code|source code]]のどこからでも、クエリ'''<syntaxhighlight lang="pascal" inline>Status := <ToggleBox>.Checked;</syntaxhighlight>'''で有効か、無効を調べることができる。「有効(Checked)」を通常のブール値として用いることができる。そのため、'''<syntaxhighlight lang="pascal" inline><ToggleBox>.Checked := True;</syntaxhighlight>'''と割り当てることが可能である。<br />
<br />
===簡単な例===<br />
* 新しい[[Application|アプリケーション]]を作り[[TForm|Form]]に3つのTToggleBoxesを配置する。<br />
* ToggleBox1...3のキャプションを「赤」、「緑」、「青」とし、それぞれを''tbRed''、''tbGreen''、''tbBlue''と変える。<br />
* [[TButton]]をフォームに追加し、そのキャプションを「青に塗る」と変え、''btnPaint''と名づける。<br />
* TButtonに対する''OnClick''イベントを作る:オブジェクトインスペクタへ移動し、''OnClick''イベントを選択し、[...]をクリックするか、フォーム上でそれをダブルクリックする。<br />
*''btnPaint''の イベントハンドラに以下のコードを加える:<br />
<syntaxhighlight lang="pascal" ><br />
procedure TForm1.btnPaintClick(Sender: TObject);<br />
var<br />
aColor: TColor;<br />
begin<br />
aColor:=0; //Form1のToggleboxの背景色をToggleboxに従って変える。<br />
if tbRed.Checked then aColor:=aColor + $0000FF;<br />
if tbGreen.Checked then aColor:=aColor + $00FF00;<br />
if tbBlue.Checked then aColor:=aColor + $FF0000;<br />
Color := aColor; //<Formular>.Colorプロパティの変更はformの書き直しを引き起こす<br />
end;<br />
</syntaxhighlight><br />
* [[Program|プログラムを起動する]]、このように見えるはずだ:<br />
<br />
[[image:ToggleBoxExample1.png]] -> [[image:ToggleBoxExample2.png]]<br />
<br />
===イベント===<br />
先の例との違いは、ボタンのクリックでフォームが書き換えられないが、すでにトグルボタンの1つ自動的にその1つがクリックされていることだ。<br />
<br />
先の例を、そのソースコードの''OnClick''イベントハンドラのを削除することによって変更することができる。また、簡単に新しい例を作ることができる:<br />
* 新しいフォームアプリケーションを作り、フォームに3つのTToggleBoxを配置する。<br />
* ToggleBox1...3のキャプションを「赤」、「緑」、「青」とし、それぞれを''tbRed''、''tbGreen''、''tbBlue''、即ち、'''<syntaxhighlight lang="pascal" inline>TForm1.tbRedChange(Sender: TObject);</syntaxhighlight>'''とし、他のToggleBoxも同様にそれに倣う:<br />
** フォームで''tbRed''をダブルクリックするか、フォームで''tbRed''を選択し、オブジェクトインスペクタのそのイベントタブ移動し、''OnChange''イベントを選び、[...]をクリックする。<br />
** それで[[Procedure|プロシージャ]] ''tbRedChange''ができる。<br />
** さらに、フォームの''tbGreen''を選択する。<br />
** オブジェクトインスペクタのそのイベントタブに移動し、''OnChange''イベントを選び、隣のコンボボックスの''tbRedChange''を選択する。<br />
** そして、フォーム上の''tbBlue''を選択、同様に、''tbGreen''へと進む。<br />
* ''<ToggleBox>.Checked''により、トグルボタンの''OnChange''イベントをフォームの色にする、こう変える:<br />
<syntaxhighlight lang="pascal" ><br />
procedure TForm1.tbRedChange(Sender: TObject); <br />
var<br />
aColor: TColor; <br />
begin<br />
aColor:=0; //トグルボックスによってForm1の背景色を設定する。<br />
if ToggleBox1.Checked then aColor:=aColor + $0000FF;<br />
if ToggleBox2.Checked then aColor:=aColor + $00FF00;<br />
if ToggleBox3.Checked then aColor:=aColor + $FF0000;<br />
Color := aColor; //<Formular>.Colorプロパティの変更はフォームの再描画を引き起こす<br />
end; <br />
</syntaxhighlight><br />
<br />
==以下も参照のこと==<br />
* [[doc:lcl/stdctrls/ttogglebox.html|TToggleBox doc]]<br />
* [[TButton/ja|TButton]]<br />
* [[TCheckBox/ja]]<br />
* [[TRadioButton/ja]]<br />
<br />
{{LCL Components/ja}}</div>Aribenhttps://wiki.freepascal.org/TMemo/jaTMemo/ja2024-03-17T13:43:39Z<p>Ariben: /* 以下も参照のこと */</p>
<hr />
<div>{{TMemo}}<br />
<br />
{{ Japanese Menu }}<br />
<br />
'''TMemo''' [[image:tmemo.png]]は複数行を編集できるコントロールである。[[Component Palette/ja|コンポーネントパレット]]タブの[[Standard tab/ja|Standardタブ]]から利用できる。<br />
<br />
==使い方==<br />
TMemoを用いるには[[TForm|form]]の''Standard''コンポーネントパレットで選択しフォーム上でクリックすればよい。このテキストボックスで実行時に複数行のテキストを編集できる。<br />
<br />
例えば、フォーム、''Form1''へTMemo ''Memo1''を加えると[[String]]に'''<code>Memo1.Text:='これは1行のテキストです';</code>'''と割り当てることができる。<br />
<br />
また、'''<code>myString:=Memo1.Text;</code>'''として、保存されたテキスト''Memo1''をソースの中のどこでも使うことができる。<br />
<br />
複数行のテキスト、'''<code>Memo1.Text:=' これは '+LineEnding+' 複数行の '+LineEnding+' テキスト '+LineEnding+' です ';</code>'''を割り当てることも可能である。<br />
<br />
===TStringsもしくはTStringListを割り当てる===<br />
通常、TMemoにテキストを割り当てるには、[[TStringList-TStrings Tutorial|TStringList]]、もしくはその親の[[TStringList-TStrings Tutorial|TStrings]]を利用する。以下の例([[TForm|form]] ''Form1''とTMemo ''Memo1''を用いて挿入された[[TButton/ja|TButton]] ''Button1''イベントハンドラで)はこれを示している:<br />
<br />
<syntaxhighlight lang=pascal><br />
procedure TForm1.Button1Click(Sender: TObject);<br />
var<br />
myStringList: TStringList;<br />
begin<br />
myStringList:=TStringList.Create; //StringListを作る<br />
myStringList.Add('This is the first line.'); //1行加える<br />
myStringList.Add('This is the second line.');<br />
myStringList.Add('This is the third line.');<br />
myStringList.Add('etc.');<br />
Memo1.Lines.Assign(myStringList); //テキスト内容を割り当てる<br />
myStringList.Free; //StringListを解放<br />
end;<br />
</syntaxhighlight><br />
<br />
===直接行を挿入する===<br />
この例ようにメモの内容を直接加えることもできる:<br />
<br />
<syntaxhighlight lang=pascal><br />
procedure TForm1.Button1Click(Sender: TObject);<br />
begin<br />
Memo1.Lines.Clear; //Memo1のすべての行を削除<br />
Memo1.Lines.Add('This is the first line.'); //1行加える。<br />
Memo1.Lines.Add('This is the second line.');<br />
Memo1.Lines.Add('This is the third line.');<br />
Memo1.Lines.Add('etc.');<br />
end;<br />
</syntaxhighlight><br />
<br />
===行を読む===<br />
特定の行に何が入っているがを知りたい場合には、直接'''<code>myString:=Memo1.Lines[Index];</code>'''で調べることができる。注意、''TMemo.Lines''はゼロから始まっている。即ち、最初の行は: '''<code>myString:=Memo1.Lines[0];</code>'''となる。<br />
<br />
続く例はさらにTButton ''Button2''を加えて、以下のように3つ目の行を表示している:<br />
<br />
<syntaxhighlight lang=pascal><br />
procedure TForm1.Button2Click(Sender: TObject);<br />
begin<br />
ShowMessage(Memo1.Lines[2]);<br />
end;<br />
</syntaxhighlight><br />
<br />
===テキストを選択する===<br />
テキスト部分をマウスの左ボタンを押し続けるか、[Shift]キーを押すことで、マウスやキーボードでテキストを選択することができる。このテキスト[[String]]をこのように表示することができる:<br />
<br />
<syntaxhighlight lang=pascal><br />
procedure TForm1.Button2Click(Sender: TObject);<br />
begin<br />
ShowMessage(Memo1.SelText); <br />
end;<br />
</syntaxhighlight><br />
<br />
===テキストを検索する===<br />
<br />
以上の例とは対照的に、TMemoにある([[String]])を探し、その場所を返すこともできる: '''<code>Position:=Memo1.SelStart;</code>'''<br />
<br />
以下の例ではmemoのなかにあるテキストを探し、さらに探している:<br />
* [[TEdit]] ''Edit1''、TMemo ''Memo1''、[[TButton/ja|TButton]] ''Button1'' と ''Button2''を持つ新しいアプリケーションを作る。<br />
* Uses節に '''LCLProc''' と '''strutils''' を加える。<br />
* [[TMemo#Insert lines directly|Insert lines directly]]例のように、''Button1''の''OnClick''イベントを何らかのテキストで埋める<br />
* ソーステキストエディタで以下の関数を(ドイツのLazarusフォーラム [http://www.lazarusforum.de/viewtopic.php?p=39260#p39260]に基づく)入力する:<br />
<br />
<syntaxhighlight lang=pascal><br />
// FindInMemo: 探す文字列が見つかった場所を返す<br />
function FindInMemo(AMemo: TMemo; AString: String; StartPos: Integer): Integer;<br />
begin<br />
Result := PosEx(AString, AMemo.Text, StartPos);<br />
if Result > 0 then<br />
begin<br />
AMemo.SelStart := UTF8Length(PChar(AMemo.Text), Result - 1);<br />
AMemo.SelLength := Length(AString);<br />
AMemo.SetFocus;<br />
end;<br />
end;<br />
</syntaxhighlight><br />
<br />
* ここで、''Button2''のイベントハンドラで''OnClick''に以下のコードを加える:<br />
<br />
<syntaxhighlight lang=pascal><br />
procedure TForm1.Button2Click(Sender: TObject);<br />
const<br />
SearchStr: String = ''; // 探す文字列<br />
SearchStart: Integer = 0; // 探す文字列の最後の場所<br />
begin<br />
if SearchStr <> Edit1.Text then begin // Falls sich der zu suchende String geändert hat<br />
SearchStart := 0;<br />
SearchStr := Edit1.Text;<br />
end;<br />
SearchStart := FindInMemo(Memo1, SearchStr, SearchStart + 1);<br />
<br />
if SearchStart > 0 then<br />
Caption := 'Found at position['+IntToStr(SearchStart)+']!'<br />
else<br />
Caption := 'No further finds!';<br />
end;<br />
</syntaxhighlight><br />
* 実行時に''Button1''でmemoを埋め、''Edit1''に探されるべきテキストを入れ、''Button2''でそれらを探す、探し続けることができる。<br />
<br />
==== EM_SCROLLCARET ====<br />
Windowsで用いられているように EM_SCROLLCARET のようなメッセージはLazarusでは使えないので、別法が必要である...<br />
<br />
===保存と読み込み===<br />
全く簡単に、[[TStringList-TStrings Tutorial|TStrings]]クラスのメソッド、''SaveToFile''と''LoadFromFile''を用いて、memoの内容を保存、読み込みできる。<br />
<br />
以下の例でどのようにするかを示す:<br />
<br />
* TMemo ''Memo1''と3つのボタン、[[TButton/ja|TButton]] ''Button1''、''Button2''、''Button3''を持つ新しいアプリケーションを作る。<br />
* さらに、コンポーネントパレット''Dialogs''から[[TSaveDialog]]と[[TOpenDialog]]をとり、フォームに置く。<br />
* ''Button1''のキャプション「メモを記入」へ変える。<br />
* ''Button1''の''OnClick''イベントハンドラで、[[TMemo#Insert lines directly|Insert lines directly]]の例にあるように、何かのテキストで、memoを埋める。<br />
* ''Button2''のキャプションを「メモを保存」と変える。<br />
* ''Button3''のキャプションを「メモを開く」と変える。<br />
* これで、ボタンの''OnClick''イベントハンドラを変更できる。<br />
<br />
<syntaxhighlight lang=pascal><br />
procedure TForm1.Button2Click(Sender: TObject);<br />
begin<br />
if SaveDialog1.Execute then<br />
Memo1.Lines.SaveToFile(SaveDialog1.FileName);<br />
end;<br />
<br />
procedure TForm1.Button3Click(Sender: TObject);<br />
begin<br />
if OpenDialog1.Execute then<br />
Memo1.Lines.LoadFromFile(OpenDialog1.FileName);<br />
end; <br />
</syntaxhighlight><br />
<br />
==以下も参照のこと==<br />
* [[doc:lcl/stdctrls/tmemo.html|TMemo doc]]<br />
* [[RichMemo|TRichMemo]] - Like Delphi TRichEdit component: formatted text (color, size, etc.)<br />
* [[TListBox]] - A scrollable list of strings<br />
<br />
{{LCL Components/ja}}</div>Aribenhttps://wiki.freepascal.org/TEdit/jaTEdit/ja2024-03-17T13:40:06Z<p>Ariben: /* 以下も参照のこと */</p>
<hr />
<div>{{TEdit}}<br />
<br />
{{ Japanese Menu }}<br />
<br />
'''TEdit''' [[image:tedit.png]]は1行編集のコントロールである。[[Component Palette/ja|コンポーネントパレット]]の[[Standard tab/ja|Standardタブ]]にある。<br />
<br />
==使い方==<br />
<br />
TEditはコンポーネントパレットの[[Standard tab/ja|Standardタブ]]にあるTEditアイコンをクリックし、フォーム[[TForm|form]]上で1回クリックすることで加えることができる。これで、実行時にこの1行テキストフィールドを編集できる。<br />
<br />
もし、このテキストを別の場所で使いたいときは、他の[[String]]のように用いることができる。<br />
<br />
例えば、もしTEdit ''Edit1''をフォームに加えると、<code>myString := Edit1.Text;</code>を用いることができる。<br />
<br />
もし、アプリケーションの起動時TEdit ''Edit1''の中のデフォルトテキスト(例えば、''Edit1'')をほかのものを表示するようにしたいなら、以下のように進めることができる:<br />
* フォーム上のTEditをクリックによって選択する。<br />
* オブジェクトインスペクタのプロパティタブに移動する。<br />
* プロパティ'''Text'''を選択し、隣の入力フィールドを変更する。<br />
* 同様にして、プロパティ'''Name'''を選択し、TEditをましな名前にする。<br />
<br />
===パスワード入力===<br />
<br />
TEditを簡単にパスワードを入力に用いることができる。このようにして、実際に入力した[[Char]]に代わり、パスワード文字を表示させる。<br />
<br />
簡単な例:<br />
<br />
* 新しいTEdit TEdit ''Edit1''を持つGUIアプリケーションを作り、TButton ''Button1''をフォームに置く。<br />
* オブジェクトインスペクタで''Edit1''のパスワード文字プロパティを、1つのアスタリスク( * )にする。<br />
* ''Button1''の''OnClick''イベントハンドラは入力されたパスワードを: <code>ShowMessage(Edit1.Text);</code>と示す。<br />
<br />
===テキストヒント===<br />
<br />
例えば、検索語を入力できる検索ボックスに入力したことはあるだろうか。そして使われてないときは、検索語ボックスはそれが何のためにあるか知らせるために「検索」のようなものを表示しているのを見たことはあるだろうか。そう、TEditはこの目的のためにTextHintと呼ばれるプロパティを持っている。TextHintは通常の「Text」が空でコントロールが使用されていない場合は、「検索」メッセージが表示される。たいていの部品ではTextHintはユーザーがタイプを始めると自動的にそこから消える。この例外はGTK2/3で、コントロールがフォーカスを得ると直ちに、中身を消し去る。<br />
<br />
TextHintからのテキストは通常のテキストより、幾分灰色がかっており、そのためユーザーは何か特別なものと気づく。大方の人はこのインタフェースを直感的に理解する。<br />
<br />
==要望事項==<br />
<br />
===TEditの埋め込まれたボタン/他のコントロール===<br />
<br />
あらゆる種類のコントロールをTEditに埋め込むことができるのはWinAPIの特性である。<br />
<br />
考慮事項<br />
<br />
* この特性はすべての部品で本来サポートされていない。例えば、GtkEntryがコンテナに由来しないのでGtk2/Gtk3では不可能である。SpinEditコントロールはGtk2の中で特別なクラスである(これは[[TSpinEdit]]がそれ自身のWSクラスを持つ主たる理由である)。<br />
<br />
* 埋め込まれたコントロールの配置に左、あるいは上方プロパティを設定することはできない(これは通常発生する)。そのかわり、「整列(Align)」プロパティを使うべきである。<br />
<br />
<syntaxhighlight lang="delphi"><br />
button1.Parent:=edit1;<br />
button1.Width:=20;<br />
button1.Align:=alRight;<br />
button1.Constraints.MaxHeight:=18; //edit1.Height;<br />
</syntaxhighlight><br />
<br />
* 「Text」エントリフィールドはTEditプログラムによって制限される:もしくは部品によって自動的に行われるべきである<br />
<br />
このような制限ないと、入力されたテキストはボタンの「下側」に行ってしまう。<br />
<br />
[[Image:edit1.gif]]<br />
<br />
もし純粋なWinAPIを用いると、これは EM_SETMARGINS メッセージを使用することで行われる:<br />
<br />
<syntaxhighlight lang="delphi"><br />
Uses<br />
Windows, ...<br />
<br />
...<br />
<br />
SendMessage(Edit1.Handle, EM_SETMARGINS, EC_LEFTMARGIN or EC_RIGHTMARGIN, MakeLParam(0, button1.Width))<br />
</syntaxhighlight><br />
<br />
[[Image:edit2.gif]]<br />
<br />
DelphiVCLはMarginsプロパティを提供するが、これは EM_SETMARGINS にはマップされず、VCLで異なる意味を持つ。<br />
<br />
==以下も参照のこと==<br />
* [[doc:lcl/stdctrls/tedit.html|TEdit doc]]<br />
* [[TMemo]] - 複数行のテキスト編集ボックス<br />
* [[TLabeledEdit]] - TEditにラベルがついた編集フィールド<br />
* [[TMaskEdit]] - マスクのついた編集フィールド<br />
* [[TSpinEdit]] - 長さが制限された整数のための編集フィールド<br />
* [[TFloatSpinEdit]] - 長さが制限された浮動小数点タイルのための編集フィールド<br />
* [[TEditButton]] - [[TSpeedBtn]]をボタンとして持つTEditにような編集フィールド<br />
* [[TFileNameEdit]] - ファイル名を入力するために[[TOpenDialog]]がつけられた編集フィールド<br />
* [[TDirectoryEdit]] - ファイルパスを入力するために[[TSelectDirectoryDialog]]がつけられた編集フィールド<br />
* [[TDateEdit]] - 日付を入力するために[[TCalendarDialog]](カレンダー)につけられた編集フィールド<br />
* [[TCalcEdit]] - 数字を入力するために[[TCalculatorDialog]] (電卓)につけられた入力フィールド<br />
* [[TTIEdit]] - RTTI可能な入力フィールド<br />
<br />
{{LCL Components/ja}}</div>Aribenhttps://wiki.freepascal.org/TLabel/jaTLabel/ja2024-03-17T13:26:48Z<p>Ariben: /* 以下も参照のこと */</p>
<hr />
<div>{{TLabel}}<br />
<br />
{{ Japanese Menu}}<br />
<br />
'''TLabel''' [[image:tlabel.png]]は1、あるいは複数行のテキストアイテムを他のコンポーネントに作るコンポーネントである。TLabelは[[TGraphicControl]]より派生し、[[Component Palette/ja|コンポーネントパレット]]の[[Standard tab/ja|Standardタブ]]より利用できる。<br />
<br />
==使い方==<br />
TLabelは[[TForm|forms]]で用いることのできるもっとも基本的なコンポーネントの1つである。ほとんどのラベルは、例えば、[[TEdit|Edit fields]]、[[TMemo|Memos]]、[[TStringGrid|StringGrids]]などといった他のコンポーネントのマーキングである。TLabelは様々な利用可能なイベントをもたらすが、ほとんどの場合必要とされない。<br />
<br />
StandardコンポーネントのTLabel(テキストシンボルAbc)をクリックすることにより、フォームにラベルを加えることができ、フォーム上にクリックして配置することができる。<br />
<br />
フォームに新しく挿入された、デフォルトラベル''Label''を変更するために、以下のように進めることができる:<br />
* フォーム上で1度クリックし、TLabelを選択する。<br />
* オブジェクトインスペクタタブのプロパティに移動する。<br />
* プロパティ、'''Caption'''を選択し、隣の編集フィールドで変更する。<br />
* 同様にしてプロパティ、'''Name'''を選択し、よりよい名前に変更する。<br />
<br />
==実行時にキャプションを変更する==<br />
もちろん、実行中にキャプション(表示されるテキスト)を変えることができる。<br />
<br />
以下の例はこれを示している:<br />
* 新しい[[Form_Tutorial/ja#初めてのGUIアプリケーション|GUIアプリケーション]]フォーム、''Form1''を作る。このフォームにStandardコンポーネントタブでふさわしいコンポーネント、[[TButton/ja|TButton]]、 ''Button1''と[[TLabel/ja|TLabel]]、''Label1''を選択し、''Form1''上でクリックする(ラベルはボタンの上にあるはずである)。<br />
* ''Button1''上で単にダブルクリックすることで、''Button1''に対する[[Event_order|イベントハンドラ]]を作る。<br />
* ''Button1''のOnClickイベントハンドラのコードに以下の行を挿入する:<br />
<syntaxhighlight lang=pascal><br />
procedure TForm1.Button1Click(Sender: TObject);<br />
const Cnt: Integer = 0; //何回ボタンがクリックされたか決めるカウンタ<br />
begin<br />
inc(Cnt); //カウンタを1インクリメント<br />
Label1.Caption:='Button was clicked ' + //Label1のキャプションにテキストをを書き込む<br />
IntToStr(Cnt) + ' times';<br />
end;<br />
</syntaxhighlight><br />
* プログラムを起動しボタンをクリックすることでラベルが変わることを試そう。<br />
<br />
== 右揃えしたラベルのDelphiとの非互換性==<br />
* Delphiでは Alignment=taRightJustify で自動的にサイズ変更されるが、Anchors=[akLeft,...]は左向きに伸びる。LCLでは、Lazarus 2.3.0からそれらは右向きに伸びる。<br />
* 理由: LCLでは大きな伸長なしに不可視のラベルに対してもまた、その振る舞いを実装することが不可能であった。LCLは同様の効果をもたらすコーントロールに基づく異なる、より一般的な特徴を持たせてある(以下の救済策を見ること)。そのため、この機能を移殖して、LCLコードをいたずらに複雑かつ、バグの元とにする、必要も要求もないとした。<br />
* 救済策: 第2のコントロールにLCLアンカリングを使う。ラベルの右側を他のコントロールにアンカーさせる。そうすると自動サイズ化されたラベルが左に伸長するが、手本となるコントロールなしに、親が、単純なakRightアンカーを終えたようにリサイズされるとき、右には移動しない。<br />
<br />
==コメント==<br />
複数行のテキストを表すため、行の折り返しの目印として、ふさわしい場所に''[[End of Line|LineEnding]]''を配置することができる。<br />
<br />
例:<br />
<syntaxhighlight lang=pascal><br />
Label1.Caption := 'This' + LineEnding + 'is' + LineEnding + 'a' + LineEnding + 'multiline' + LineEnding + 'text';<br />
</syntaxhighlight><br />
<br />
==以下も参照のこと==<br />
* [[doc:/lcl/stdctrls/tlabel.html|TLabel doc]]<br />
* [[TStaticText]]<br />
<br />
{{LCL Components/ja}}</div>Aribenhttps://wiki.freepascal.org/TPopupMenu/jaTPopupMenu/ja2024-03-17T13:19:38Z<p>Ariben: /* 以下も参照のこと */</p>
<hr />
<div>{{TPopupMenu}}<br />
<br />
{{Japanese Menu}}<br />
<br />
'''TPopupMenu''' [[image:tpopupmenu.png]]はマウスの右ボタンがクリックされるとポップアップするメニューパネルである。<br />
<br />
これは目に見えないコンポーネントで、即ち、もし[[Component Palette/ja|コンポーネントパレット]]の[[Standard tab/ja|Standardタブ]]から選ばれ、フォームの上に置かれたとき、ランタイムに現れない。その代わり、メニューエディタによって構造定義されたメニューバーが現れる。<br />
<br />
Menu Editorを見るには、Main Menuアイコンをフォーム上で右クリックする。<br />
<br />
==ポップアップメニューを作る==<br />
<br />
以下の道筋で、[[TForm|Form]]コンポーネントにポップアップメニューの追加の仕方を示す:<br />
* 新しい[[Form_Tutorial/ja#初めてのGUIアプリケーション |GUIアプリケーション]]を作り、[[TImage/ja|TImage]]をそのフォームに挿入する。このため、コンポーネントパレット''Additional''でTImageを選択し、フォームの上でクリックする。これで''Image1''の名前でTImageがフォーム上に配置される。<br />
* オブジェクトインスペクタに移動(''Image1''であるはずだ)し、''Align''プロパティを選択する。隣のコンボボックスで''alClient''を1列に調節する(Image1はフォームのサイズに調節される)。<br />
* フォームの上にTPopupMenu(stanndardタブ)を配置する(もし可能なら「Image1」上に、そうすればこれが画像に1つとわかる)。コンポーネント''PopupMenu1''は(ドロップダウンメニューとコンポーネントの名前の表示と直角に)フォーム上に表示される。<br />
* 「PopupMenu1」を右クリックすると、ポップアップメニューが現れる。最初の項目 '''Menu Editor'''をクリック<br />
* ''New Item1''のキャプションでメニューアイテムがすでに作られており、メニューエディタウィンドウで開く。おそらくこれを変更したいだろう、そのためにはクリックし、オブジェクトインスペクタに移動する。<br />
* オブジェクトインスペクタでMenuItem1から何かふさわしい名前にするためNameプロパティを変更する。これをLoadメニューと呼ぶことにする。そこでNameを'''popLoad'''とタイプし、エンターを押す。<br />
* New Item1より、ましなものとしたい、そこでCaptionプロパティに行き'''Load'''とタイプし、エンターを押す。<br />
* さらにもう1つの入力項目がある。メニューエディタウインドウに戻り、''Load''を右クリックする。ポップアップメニューが現れる。<br />
* Insert ''New Item After''をクリックすると、''New Item2''という名前の新たなメニューが現れる。前の2つのアイテムで説明した通り、この名前を'''popStretch'''、キャプションを'''Stretched'''へとオブジェクトインスペクタで変更する。<br />
* メニューへの入り口を忘れていることに気づくが、悪いことではない、メニューエディタに戻る。'''Load'''を右クリックするか、'''Insert New Item (after)'''をクリック、または'''Stretched'''で右クリックし、'''Insert New Item (before)'''をクリックする。<br />
* キャプションを'''Centered'''名前を'''popCenter'''変更する。<br />
* 必要なそれぞれのメニューアイテムが終端で閉じるようにメニューエディタで調節する。<br />
* すべてのメニューを加えたとき、どのコンポーネントが結び付くべきかまだ設定しなければならない。この場合、これはフォームに最初に配置したTImage、''Image1''であるべきである。<br />
* フォーム上の''Image1''を選択し、オブジェクトインスペクタのプロパティ'''PopupMenu'''へ移動する。そこで、隣のコンボボックスの''PopupMenu1''を選択する。<br />
* 実行中は画像を右クリックするといつもポップアップメニューが現れるだろう。<br />
<br />
これで実行中メニューが現れ、ユーザーがメニューをクリックすることが可能となる。これは実際何もしない。何かをするメニューアイテムを作るには、それぞれのメニューについてクリックに反応する[[Event_order|events]]を加えなければならない。<br />
<br />
以下にオブジェクトインスペクタを用いてメニュークリックイベントの編集の仕方を説明する。<br />
<br />
==実際に何かをするメニューを作る==<br />
* メニューエディタにもどり、クリックして'''Load'''メニューアイテムをクリックして選択する。そしてオブジェクトインスペクタウインドウへ移動し、'''events'''タブを選択する。変えたいイベントだけを変える、それは今、空の''OnClick''である。もし用いるべき[[Event_order|EventHandler]]をすでに持っているなら、それらを使うことができるし、それに応じて選択することもできる、さもなくば、Lazarusで作ることもできる。右側に3つの点があるボタンがある。クリックする。そうすると新しいプロシージャ(新しく生成したイベントハンドラ)がコードの中に生成され、ソーステキストエディタに対する変化が見て取れる。このプロシージャはこのように見えるだろう:<br />
<syntaxhighlight lang=pascal><br />
procedure TForm1.popLoadClick(Sender: TObject);<br />
begin<br />
<br />
end;<br />
</syntaxhighlight><br />
<br />
* '''begin'''と'''end'''間にメニューエントリ''Load''に対するコードを挿入することができる。<br />
<br />
この場合フォームの上にTOpenDialogコントロールを挿入し、この目的ンために標準ダイアログを使うことができるだろう:<br />
<br />
* そのため、[[TOpenDialog]]コントロールをフォームに入れ(コンポーネントパレット ダイアログ)、その名前は''OpenDialog1''である。プロシージャを以下に変更する:<br />
<br />
<syntaxhighlight lang=pascal><br />
procedure TForm1.popLoadClick(Sender: TObject);<br />
begin<br />
if OpenDialog1.Execute then //ファイルが選択された場合のみ<br />
try //try<br />
Image1.Picture.LoadFromFile(OpenDialog1.Filename); //そのファイルを読み込む<br />
except<br />
end;<br />
end;<br />
</syntaxhighlight><br />
<br />
* 他のメニューアイテムも同様のプロシージャで、それぞれのイベントハンドラを作り、以下のコードを挿入する:<br />
<br />
<syntaxhighlight lang=pascal><br />
procedure TForm1.popStretchClick(Sender: TObject);<br />
begin<br />
popStretch.Checked := not popStretch.Checked; //マーク/チェック on/off<br />
Image1.Stretch := popStretch.Checked; //Image1 引き伸ばし yes/no<br />
end;<br />
<br />
procedure TForm1.popCenterClick(Sender: TObject);<br />
begin<br />
popCenter.Checked := not popCenter.Checked; //マーク/チェック on/off<br />
Image1.Center := popCenter.Checked; //Image1 中央配置 yes/no<br />
end;<br />
</syntaxhighlight><br />
<br />
* これで、このサンプルを{{keypress|F9}}で実行し、右クリックでポップアップメニューが開き、''Load''をクリックする。すると選んだ画像が読み込まれる。画像を取り込んだら、他のメニューエントリを試してみよう。<br />
<br />
==自己ポップアップ==<br />
<br />
特定のコンポーネント、異なるイベントでは右クリックでポップアップを表示させたくない場合があるかもしれない。その時は'''<code>PopupMenu.PopUp</code>'''を実行することができる。<br />
<br />
簡単な例:<br />
<br />
* 新しい[[Form_Tutorial#The_first_GUI_application|GUI application]]を作り、そのフォームにTPopupMenu ''PopupMenu1''と[[TButton]] ''Button1''を加える。<br />
* 新しいメニューエントリ''PopupMenu1'' ([[TPopupMenu#Creating_a_PopupMenu|Creating a PopupMenu]]を見ること)。<br />
* ''Button1''のOnClickイベントを作成し、以下のコードを書く:<br />
<br />
<syntaxhighlight lang=pascal><br />
procedure TForm1.Button1Click(Sender: TObject);<br />
begin<br />
PopupMenu1.PopUp; //ポップアップメニューを表示<br />
end;<br />
</syntaxhighlight><br />
* プログラムを実行すると、ボタンをクリックすることにより、ポップアップメニューが呼ばれる。<br />
<br />
== ポップアップメニューの結果 ==<br />
同じポップアップメニューは、ポップアップの呼び出し元を取り戻すため、''PopupComponent''を用いて複合コントロールにより使うことができる。<br />
<br />
<syntaxhighlight lang=pascal><br />
...<br />
Uses <br />
... Clipbrd...<br />
<br />
procedure TfrmIniPrevMain.pmnuMenuItem1Click(Sender: TObject);<br />
begin<br />
if pmnuMenuItem1.PopupComponent.ClassType = TMemo then<br />
begin<br />
Clipboard.AsText := TMemo(pmnuClipBoard.PopupComponent).Text;<br />
end;<br />
if pmnuClipBoard.PopupComponent.ClassType = TEdit then<br />
begin<br />
Clipboard.AsText := TEdit (pmnuClipBoard.PopupComponent).Text;<br />
end;<br />
end; <br />
</syntaxhighlight><br />
<br />
== 以下も参照のこと ==<br />
<br />
* [[doc:lcl/menus/tpopupmenu.html|TPopupMenu doc]]<br />
* [[TMainMenu]] <br />
<br />
{{LCL Components/ja}}</div>Aribenhttps://wiki.freepascal.org/TMainMenu/jaTMainMenu/ja2024-03-16T23:46:48Z<p>Ariben: /* 以下も参照のこと */</p>
<hr />
<div>{{TMainMenu}}<br />
<br />
{{Japanese Menu}}<br />
<br />
>> [[LCL Components]] >> TMainMenu<br />
<br />
'''TMainMenu''' [[image:tmainmenu.png]]はフォームでメインメニューを提供する[[Component Palette/ja|コンポーネントパレット]]の[[Standard tab/ja|Standardタブ]]からの見ることのできないコンポーネントである。<br />
<br />
==概要==<br />
フォームを設計するときに様々なメニューアイテムによって選ばれる、ほとんどのウインドウの先頭に現れるメインメニューである。<br />
<br />
メニューエディタを見るにはフォームのメインメニューアイコンを右クリックすること。<br />
<br />
==約束事==<br />
''mnu''、''menu''で始まる、あるいはmenuのそのものをメニュー(menu)と名付けるのは一般的な慣習である。サブメニューがそれに含まれるメニューのプリフィクスとともに続く。例えば、「編集(Edit)」にある「切り取り(Cut)」サブメニューはたいてい''mnuEditCut''もしくは、''menuEditCut''と名付けられる。これは今から6か月後に変更する必要が生じたときに、それらを中に入れる仕方の記憶を助け、覚えやすいが、''慣習''であり、強制ではないことに注意すること。しかし、このようにすることは後々変更したり、しばらくコードを見ていないときに、あるいは、書かれたプログラムをメンテナンスしなければならない、誰かほかの人間にとって、おそらくそれが何をしているかを理解する手助けになるだろう。<br />
<br />
始めてみよう<br />
<br />
==メニューを作成する==<br />
# コンポーネントバーからTMainMenuを選び、フォーム上でそれをクリックするが、マウスボタンは離さずに押したまま、箱を描いてマウスボタンを離す。そのコンポーネントがフォームに現れるだろう。これはドロップダウンメニューとデフォルトのコンポーネント名が''MainMenu1''となった四角形が現れるだろう。<br />
#もし'''MainMenu1'''と言う名前が気に食わなければ、オブジェクトインスペクタウィンドウに移動して、よりよいと考えるものにNameプロパティを変更する。ここでは''XMenu''に変更する。Nameプロパティの左の箱に'''XMenu'''とタイプして、エンターを押す。コンポーネントの名前が変更される。<br />
# XMenuを右クリックすると、ポップアップメニューが現れる。ここで、必要なのは最初のセクション、'''Menu Editor'''である。それをクリックする。<br />
# Menu Editorウィンドウが「New Item1」のキャプションを持つ、すでに作られたメニューアイテムが開く。いつも見ている「ファイル 編集 表示 ヘルプ」のトップレベルメニューとなり、おそらくこれを変更したいだろう。そのためにはクリックし、オブジェクトインスペクタに移動する。<br />
# オブジェクトインスペクタでNameプロパティをMenuItem1からよりふさわしいものに変更する。これをFileメニューと呼ぶことにする。そこで'''mnuFile'''とタイピングし、エンターを押すことでこれを変更する。<br />
# New Item1よりも良い名前が欲しいので、Captionプロパティに移動し、'''&File'''とタイプし、エンターを押す。名前の前のアンパサンド'''&'''はAltキーと下線が引かれたキーを押すことにより、メニューを開くことのできる''アクセラレータ''である。このメニューに対するキャプションを'''<u>F</u>ile'''へと変更する。この時点で、1つのトップレベルメニュを加えたことになる。<br />
# Menu Editorウインドウに戻る。<u>F</u>ileをクリックし、次に右クリックする。ポップアップメニューが現れる。''Insert New Item After''をクリックし、''New Item2''という名前の新しいメニューが現れる。2つのアイテムですでに説明したように、オブジェクトインスペクタでその名前を'''mnuHelp'''、この名前を'''mnuHelp'''、キャプションを'''&Help'''に変更する。<br />
# これを<u>F</u>ileの下のメニューアイテムにする。右クリックし、'''Create Submenu'''をクリックする。ファイルメニューは矢印を持ち、# ''New Item2''という名前のサブメニューが現れる。<br />
これをそれが行う何かに関連したものに変更する、ここでは「開く」ということにする。オブジェクトインスペクタに移動し、Nameプロパティを'''mnuFileOpen'''、キャプションを'''&Open'''に変更する。<br />
# トップレベルメニュー'''<u>F</u>ile'''と'''<u>H</u>elp'''の間にまたトップレベルメニューが必要である。'''<u>F</u>ile'''を右クリックし、'''Insert New Item (after)'''するか、'''<u>H</u>elp'''を右クリックし、'''Insert New Item (before)'''をクリックすることができる。<br />
# このアイテムのプロパティをオブジェクトインスペクタで'''mnuEdit'''へ変更する。<br />
# 必要なら、それぞれのメニューとサブメニューに応じて上記を繰り返す。<br />
<br />
これで、すべてが実行時に表示され、ユーザーはメニューをクリックすることができる。これは実際には何もしない。メニューアイテムに何かをさせるときは、クリックされると反応することになっている、それぞれのメニューとサブメニューに[[Event_order|events]]を加えなければならない。通常はトップレベルメニューは反応しないが、サブメニューは反応する。メニューの反応のさせ方に2つの選択肢があり、メニューの中にイベントを挿入するか、あるいは[[TActionList]]コンポーネントを用いることもできる。TActionListを用いる主な理由はもし、ツールバーにアイコンを加えるつもりがあるならば、まず、「ファイル」そして、「開く」、「保存」、「名前をつけて保存」、「閉じる」などのメニューをサブメニューとして持ち、同様にツールバーに「新規」、「開く」、「保存」、「名前をつけて保存」ボタンがあるツールバーを持つことになる。「新規」、「開く」機能を扱う2つのルーチンを書くより、メニューとツールバー双方にTActionListを持つ。TActionListを使う仕方はほかに譲る。当面はオブジェクトエクスプローラでイベントを用いての、メニュークリックを扱う仕方を説明する。<br />
<br />
==実際に何かをするメニューを作成する==<br />
# Menu Editorウインドウに戻り、'''<u>F</u>ile'''以下にあるサブメニュー'''<u>O</u>pen'''をクリックする。オブジェクトインスペクタウインドウに行き、'''Events'''タブをクリックする。変えたいイベント何もないはOnClickのみである。あると好ましい、存在するイベントハンドラを持っているならば、用いることができるが、それはないため、Lazarusにそれを作らせることができる。3つのボタンの右に3つのドット(...)がある。これをクリックすると、新しいプロシージャがコードの中に生成され、コードウインドウにヴューが切り替わる。これは以下のように見えるだろう。<br />
<syntaxhighlight lang=pascal><br />
procedure TfrmMain.mnuFileOpenClick(Sender: TObject);<br />
begin<br />
end;<br />
</syntaxhighlight><br />
# '''begin'''と'''end'''ステートメントの間にメニューのオープンアクションを書くだろう。これはフォーム上のDaialogs tabから''TOpenDialog''コントロールを配置するかもしれない。同様のことが '''<u>S</u>ave'''、'''Save <u>a</u>s'''サブメニューを持つと適用される。<br />
# どのようにしてメニューとサブメニューを加えるかについて上で言及した点を繰り返すことになり、それぞれはユーザーによってクリックされる1つ1つについて必要ならばイベントハンドラを作るだろう。<br />
<br />
==チェックボックスメニュー==<br />
さて、チェックボックスが欲しくなったかもしれない、ユーザーがクリックするとそれはチェックマークがついたり、消えたりする。これを行う方法を議論する。<br />
# Menu Editorウインドウに移り、'''<u>E</u>dit'''をクリックする。<br />
# <u>E</u>ditの下にメニューアイテムを作ろう。右クリックし、 '''Create Submenu'''をクリックし、オブジェクトインスペクタウインドウで、もしすでに選択されていなければ、プロパティタブをクリックする。このサブメニューを'''mnuEditPreserve'''と名づけキャプションを'''P&reserve case'''とする(コピーアンドペーストが通常ALT+PとALT+Cを使うので、このサブメニューにはALT+Rを使う。これが「r」の前にアンパサンドを置いた理由である)。<br />
<br />
# デフォルト値、''チェック(checked)''をFalseにする. もしこのメニューのデフォルト状態がチェックなら、値をダブルクリックしてFalseからTrueに変えること。<br />
# '''Events'''タブを選択して、'''Click'''プロパティを選び、...ボタンをクリックする。<br />
# Lazarus はコードウインドウに切り替わり、このサブメニューに対してClickイベントを生成する。<br />
# '''begin'''と'''end'''のあいだでには、以下のような一行のみを記入すればよい:<br />
# mnuEditPreserve.checked := not mnuEditPreserve.checked ;<br />
# これが値をチェックからアンチェックに切り替える。コードの中でこのチェックされたメニューを使うことができるようにするには'''<code>mnuEditPreserve.checked</code>'''を参照すればよい (もしくはメニューの名前が何であれ、プロパティが''checked''のもの)。それはほかのどの[[Boolean]] 値に関しても同様である。<br />
<br />
==セパレータ==<br />
時には線で区切られている項目を持つメニューが必要な時がある。例えば、'''<u>E</u>dit'''メニューは'''Cut'''、'''Copy'''、'''Paste'''サブメニューを持ち、次のサブメニューの前にセパレータラインを持つかもしれない。セパレータラインを作るには、もう1つのサブメニューを作り、キャプションが1つのダッシュ(-)からなるようにすればよい。<br />
<br />
==ショートカット==<br />
もし望むのであれば、メニューに対して特定のキーの組み合わせを割り当てることができる、以下の手順である:<br />
* メニューエディタでキーボードショートカットを割り当てるメニューを選択する。<br />
* オブジェクトインスペクタでプロパティ、''ShortCut''に移動し[...]ボタンをクリックする。<br />
* メニューに望むショートカットを選択できるウインドウが現れる。<br />
* メニューのランタイムイベントハンドラはこのショートカットをこのメニューをクリックしたしたかのように呼び出す。<br />
<br />
==メニューの前の画像==<br />
もしメニューを視覚的に際立たせたい、あるいは可能なツールバーに対するメニュー項目の光学マッピングを確立したいのなら、メニューの前に画像を表示させることができる。以下の手順が必要である:<br />
* [[TForm|フォーム]]に[[TImageList|イメージリスト]]を追加する。これはコンポーネントパレット''Common Controls''で見つけられる。TImageListを選択し、Form上にクリックして配置する。''ImageList1''という名のこれでイメージリストがフォーム上に生成される。これらのイメージリストはメニューの前に表示されるすべてのシンボルや画像を含んでいる。<br />
* ''ImageList1''を右クリックし、'''ImageList Editor'''を開く。<br />
* メニューに必要なすべての画像をImageListに次々に加える。単にボタン''Add''をクリックし、相応しい画像をいつも通り加える。<br />
* ImageListに必要とされるすべての画像をすべての画像を加えたら、[OK]ボタンで選択を確認し、ImageList Editorを閉じる。<br />
* そして、MainMenuを選択しなければならず、オブジェクトインスペクタでImageListにプロパティ''Images''を設定する。単に隣のコンボボックスでImageList ''ImageList1''を選択する。<br />
<br />
* そして、メニューエディタでメニューを再び開き、画像を得たいメニューを選択する。<br />
* メニューからオブジェクトインスペクタの''ImageIndex''プロパティへ移動し隣のコンボボックスに表示されている画像を選択する。<br />
* Menu Editorで次のメニューを選択し、それに対応する画像を選択する。など。<br />
<br />
==問題: 左側にサブメニューがドロップダウンする(Windows Vista、7、10)==<br />
もし、プルダウンメニューがメインメニューアイテムの右に並び、サブメニューが左に開いたら、それはWindowsが'''Tablet PC Settings'''で'''Right-handed(右利き)'''に設定されている。これはタブレットを用い、画面で記入/押す、でメニューが直接的に表示されるときにおこる。もし右利きなら、メニューを左側に表示したいかもしれない。そうするとメニューは手の下側に現れない。通常のPC操作ではこれをデフォルトで左利きに設定されている。<br />
以下を行うことでこれを確かめることができる:<br />
* Window-key + Rを押す。<br />
* '''shell:::{80F3F1D5-FECA-45F3-BC32-752C152E456E}'''を入力しエンターを押す。<br />
* '''Other(その他)'''タブに移動する。<br />
* デフォルトが'''Left-handed(左利き)'''に設定されるべきで、メニューが右に現れるようになっており、さもなくば左に現れる。<br />
* 注意: 設定にかかわらずサブメニューの矢印はそれでもメニューの右側に現れるだろう。<br />
<br />
==ランタイムを作成する==<br />
ランタイムにTMainMenuを作るためには、フォームの所有者をTMainMenuに指定するべきである。<br />
<syntaxhighlight lang=pascal><br />
mnuMainMain = TMainMenu.Create(Form1);<br />
</syntaxhighlight><br />
(注意、親を指定することは不要であり、アプリケーションを所有者として指定することは望んだ効果が得られない)<br />
<br />
==以下も参照のこと ==<br />
* [[doc:lcl/menus/tmainmenu.html|TMainMenu doc]]<br />
* [[TPopupMenu]]<br />
* [[TActionList]]<br />
<br />
{{LCL Components/ja}}</div>Aribenhttps://wiki.freepascal.org/Standard_tab/jaStandard tab/ja2024-03-16T22:06:48Z<p>Ariben: </p>
<hr />
<div>{{Standard_tab}}<br />
<br />
{{Japanese Menu}}<br />
<br />
'''Standardタブ'''([[Component Palette/ja|コンポーネントパレット]]にある)にはフォームで用いる基本的なコンポーネントを並べてある。<br />
<br />
[[Image:Component_Palette_Standard.png|size="100%"]]<br />
<br />
{| class="wikitable sortable"<br />
|-<br />
! Icon !! コンポーネント !! 概要 !! オンラインドキュメントOnline Docs<br />
|-<br />
| [[Image:tmainmenu.png]] || [[TMainMenu/ja|TMainMenu]] || フォームの上端のメニュー<br />
||[http://lazarus-ccr.sourceforge.net/docs/lcl/menus/tmainmenu.html Link]<br />
|-<br />
| [[Image:tpopupmenu.png]] || [[TPopupMenu/ja|TPopupMenu]] || 定義済みのイベントをポップアップするコンテキストメニュー、通常マウスの右ボタンクリックによる<br />
||[http://lazarus-ccr.sourceforge.net/docs/lcl/menus/tpopupmenu.html Link]<br />
|-<br />
| [[Image:tbutton.png]] || [[TButton/ja|TButton]] || キャプションを持つボタンを表示する<br />
||[http://lazarus-ccr.sourceforge.net/docs/lcl/stdctrls/tbutton.html Link] <br />
|-<br />
| [[Image:tlabel.png]] || [[TLabel/ja|TLabel]] || 読み取り専用のテキストフィールド、編集不可<br />
||[http://lazarus-ccr.sourceforge.net/docs/lcl/stdctrls/tlabel.html Link] <br />
|- <br />
| [[Image:tedit.png]] || [[TEdit/ja|TEdit]] || 1行のテキストフィールド<br />
||[http://lazarus-ccr.sourceforge.net/docs/lcl/stdctrls/tedit.html Link]<br />
|-<br />
| [[Image:tmemo.png]] || [[TMemo/ja|TMemo]] || 複数行のテキスト編集フィールド<br />
||[http://lazarus-ccr.sourceforge.net/docs/lcl/stdctrls/tmemo.html Link]<br />
|-<br />
| [[Image:ttogglebox.png]] || [[TToggleBox/ja|TToggleBox]] || 2つの状態を持つボタン。[[TButton]]に類似するが、クリック後も残り、次のクリックで解放される。<br />
||[http://lazarus-ccr.sourceforge.net/docs/lcl/stdctrls/ttogglebox.html Link]<br />
|-<br />
| [[Image:tcheckbox.png]] || [[TCheckBox/ja|TCheckBox]] || ON/OFFボタン、チェックマークによってON状態を表す<br />
||[http://lazarus-ccr.sourceforge.net/docs/lcl/stdctrls/tcheckbox.html Link] <br />
|-<br />
| [[Image:tradiobutton.png]] || [[TRadioButton/ja|TRadioButton]] || ON/OFFボタン、他のTRadioButtonsと組み合わせて用い1つだけONとなる<br />
||[http://lazarus-ccr.sourceforge.net/docs/lcl/stdctrls/tradiobutton.html Link] <br />
|-<br />
| [[Image:tlistbox.png]] || [[TListBox/ja|TListBox]] || 選択可能な文字列の一覧を表す<br />
||[http://lazarus-ccr.sourceforge.net/docs/lcl/stdctrls/tlistbox.html Link]<br />
|-<br />
| [[Image:tcombobox.png]] || [[TComboBox/ja|TComboBox]] || それから選択される編集フィールドの組み合わせのドロップダウンリスト<br />
||[http://lazarus-ccr.sourceforge.net/docs/lcl/stdctrls/tcombobox.html Link] <br />
|-<br />
| [[Image:tscrollbar.png]] || [[TScrollBar/ja|TScrollBar]] || スライダーを移動させることにより内容をスクロールする<br />
||[http://lazarus-ccr.sourceforge.net/docs/lcl/stdctrls/tscrollbar.html Link]<br />
|-<br />
| [[Image:tgroupbox.png]] || [[TGroupBox/ja|TGroupBox]] || 物理的、概念的にグループ化されるいくつかのオブジェクトのコンテナ<br />
||[http://lazarus-ccr.sourceforge.net/docs/lcl/stdctrls/tgroupbox.html Link]<br />
|-<br />
| [[Image:tradiogroup.png]] || [[TRadioGroup/ja|TRadioGroup]] || 関連があるが、いずれかの選択が必要な、相互排他的なTRadioButtons。統合されたTRadioButtonsのTGroupBoxに似ている。<br />
||[http://lazarus-ccr.sourceforge.net/docs/lcl/extctrls/tradiogroup.html Link] <br />
|-<br />
| [[Image:tcheckgroup.png]] || [[TCheckGroup/ja|TCheckGroup]] || コンテナコンポーネントで物理的、論理的にグループ化されたアイテムのTCheckBox。<br />
||[http://lazarus-ccr.sourceforge.net/docs/lcl/extctrls/tcheckgroup.html Link]<br />
|-<br />
| [[Image:tpanel.png]] || [[TPanel/ja|TPanel]] || 他のコンポーネントに対する見ることのできるコンテナ<br />
||[http://lazarus-ccr.sourceforge.net/docs/lcl/extctrls/tpanel.html Link] <br />
|-<br />
| [[Image:tframe.png]] || [[TFrame/ja|TFrame]] || フォームまたは他のフレームに埋め込みできるコンポーネントに対するコンテナ<br />
||[http://lazarus-ccr.sourceforge.net/docs/lcl/actnlist/tframe.html Link] <br />
|-<br />
| [[Image:tactionlist.png]] || [[TActionList/ja|TActionList]] || メニュー/マウス/キーボードを扱うことに特化した[[TAction]]のリスト<br />
||[http://lazarus-ccr.sourceforge.net/docs/lcl/actnlist/tactionlist.html Link] <br />
|}<br />
<br />
== 以下も参照のこと ==<br />
* [http://lazarus-ccr.sourceforge.net/docs/lcl/stdctrls/index-4.html stdctrls doc]<br />
<br />
{{NavComponentPalette/ja}}</div>Aribenhttps://wiki.freepascal.org/Component_Palette/jaComponent Palette/ja2024-03-16T12:29:51Z<p>Ariben: </p>
<hr />
<div><noinclude>{{Component Palette}}</noinclude><br />
<br />
{{Japanese Menu}}<br />
<br />
'''コンポーネントパレット'''([[IDE]]にある)はフォームを構築する際に主に用いられるコンポーネントを表す、数多くのアイコンが並べられたツールバーである。<br />
<br />
[[Image:Component_Palette_Standard.png|size="100%]]<br />
<br />
{{NavComponentPalette/ja}}<br />
<br />
それぞれのタブはコンポーネントの機能的なグループを表す、異なるアイコンセットを表示する。それぞれのタブグループのもっとも左のアイコンは、セレクションツールと呼ばれる左斜めに傾いた矢印である。<br />
<br />
アイコンをクリックせずにコンポーネントパレット上の、どのアイコンにマウスカーソルをかざしても、コンポーネントの名称がポップアップする。それぞれの名称はTで始まっており、これは「Type」、より正確に言えばそのコンポーネントの「クラス」を表していることに注意すること。フォームに含めるためにコンポーネントを選択すると、[[Unit]](通常はTForm1全体の部分)の'''[[Interface|interface]]'''の''' [[Type|type]] '''セクションに[[Class]]が追加され、そしてそのクラスの'''instance'''(インスタンス)が''' [[Var|var]] '''セクション(通常は変数Form1として)に追加される。Form、あるいはそのコンポーネント(即ち、[[Procedure]](プロシージャ)または[[Function]](関数))によって用いられるために設計されたどの''' [[Method]]s '''(メソッド)もユニットの''' [[Implementation|implementation]] '''(実装部)に置かれる。<br />
<br />
==== パレットの用い方 ====<br />
<br />
パレットを用いるには、エディタのヴューに空きフォームがなければならない(もしなければ、ファイル -> 新規フォーム、を選択する)。使いたいコンポーネントを含む相応のアイコンをクリックし、フォーム上のコンポーネントを現したい付近をクリックする。望むコンポーネントが現れたら、マウスでそれをクリックすることで選択できる。ひとたびフォーム上で選択されれば、そのオブジェクトは、プロパティとイベントを編集できるオブジェクトインスペクタウィンドウでも選択できる。<br />
<br />
オブジェクトの外観を調整するには、マウスを用いてフォーム上の画そのものを変える、あるいはそれに対するプロパティをそのコンポーネントに対するオブジェクトエディタで調整することもできる。<br />
<br />
もし、自分自身で作った、あるいは他から得られた追加のパッケージのいずれも、コンポーネントパレットの相応の付加的タブに現れる。これらの新しいコンポーネントはデフォルトでついてくるものと同様に選択して、フォーム上で使用できる。<br />
<br />
以下のコンポーネントの一覧でユニットの記述を含むファイルへのリンクが現れる。もし、あるコンポーネントのプロパティを探したいのであれば、そのコンポーネントの継承と、それが由来する基底型のプロパティについても調べておく価値がある。例えば、[[TMaskEdit]]を理解するには、[[TCustomMaskEdit]]を検討することは意義がある。<br />
<br />
=== カスタマイゼーション ===<br />
メニュー、[Tools|Options](ツール -> オプション...)もしくは{{keypress|Crtl-Shift-O}}でコンポーネントパレットの項目の配置と外観を変えることができる。<br />
<br />
[[File:IDE Options - Environment - Component Palette.png]]<br />
<br />
=== 例 ===<br />
パレットに現れない、有用だが簡単に、[[Source code|ソース]]、 [[Program|プログラム]]で用いることができる、[[Dialog Examples|ダイアログ プロシージャ、または関数]]がある。<br />
<br />
コンポーネントを用いるいくつかの良い例はソースコードをインストールした$LazarusPath/examplesで見つかる。多くのプログラムは直接、IDEとコンポーネントパレットを用いない、またはフォーム定義ファイルから独立してダイアログや他のコンポーネントを使う方法を示している。すべてのコンポーネントは十分に、そして明示的にPascalプログラムで定義されている。他のプログラム例はIDEを十二分に活用している。<br />
<br />
これらの例を開くときにはプロジェクトとして、.lpiファイルを開くことを覚えておきたい。.pasソースコードをひらいて、「実行」を打ち込んでしまうと、このソースファイルを最後に開いたプロジェクトが何であれ、それに付け加えられてしまう。<br />
<br />
いくつかの例はそのままでは動かない: パスとファイルのパーミッションを適宜調整する必要がある。もし、これらの例のいずれかをコンパイルしたいときは、そのディレクトリに対して、読み取り/書き込み/実行権限を持っていることを確認すること。またはファイルを適切な権限を持ったディレクトリにコピーすること。<br />
<br />
一緒になっている小さなテストフォーム例とそれで利用できるコンポーネントのメニューを見るために「testall(テスト向きの(訳注1))」プログラムを実行して、そしてそれらがどのように動くか点検すること!<br />
<br />
訳注1:readmeになぞらえたものと思われる。</div>Aribenhttps://wiki.freepascal.org/Form_Tutorial/jaForm Tutorial/ja2024-03-15T15:25:02Z<p>Ariben: /* 初めてのGUIアプリケーション */</p>
<hr />
<div>{{Form Tutorial}}<br />
<br />
{{Japanese Menu}}<br />
<br />
Lazarusでフォームを用いるための短いイントロダクション。<br />
<br />
== フォームとは何か ==<br />
<br />
フォーム (class [[TForm]])は[[Application|application]]のユーザーインターフェースとなるウインドウもしくはダイアログを表す。それは他の[[LCL Components|components]](例えば、ボタン、ラベル、編集ボックス、画像など)が挿入されるコンテナである。<br />
<br />
== 初めてのGUIアプリケーション ==<br />
<br />
Lazarusのインストールが成功し、新しいアプリケーションプロジェクトを始めると、空のフォームが作られる。そうでなければ、新しい<br />
[[Overview_of_Free_Pascal_and_Lazarus#GUI_apps|GUI アプリケーション]]を メインメニュー -> プロジェクト -> 新規プロジェクト -> アプリケーション OKで作ることができる。<br />
<br />
今、新しい、全機能が使えるフォームを持つプロジェクトが生成された:<br />
<br />
[[Image:Form1_Designmodus.png]]<br />
<br />
新しく作られたプロジェクトを実行するには、単に{{keypress|F9}}キーを押す、もしくはマウスでメインメニューアイコン[[Image:Start.png]](あるいは メインメニュー: 実行 -> 実行)をクリックする。プロジェクトはコンパイル、実行される。<br />
<br />
特に面白いことが起こるわけではない。フォーム(Form1)はわずかに外見が変わり、ラスタグリッドの点々(個々のコンポーネントの位置付けの助けとなる)が消える(グリッドの点が見えてる間は、それがデザインモードにあることがわかる):<br><br />
<br />
[[Image:Form1_Designmodus.png]] -> [[Image:Form1_Runmodus.png]] <br />
<br />
次にフォームの上に[[TButton/ja|TButton]]を配することができる。これは後に第2のフォームを開くことを可能にするために使われる:<br />
<br />
[[Component Palette/ja|コンポーネントパレット]]上の[[Standard tab/ja|Standardタブ]]からTButtonを選ぶ。<br />
<br />
[[Image:TButtonStandardpalette.png]]<br />
<br />
そしてフォームをクリックする: 「Button1」の名前とキャプションでForm1にボタンが配される。<br />
<br />
このボタンに何かをさせるために、それをクリックすると、何か意図したことをするようにボタンに告げなければならない。これは単純なイベントである。このためクリックされた後に呼ばれる [[Event_order | イベントハンドラ]]が必要である。マウスに対するイベントハンドラはボタンはButton1をダブルクリックすることにより、極めて簡単に行える(もしくはオブジェクトインスペクタで、Button1 -> イベントタブ -> OnClick、次いで[...]をクリック)。これはButton1がクリックされると(設計段階ではなく[[runtime]])にいつも呼ばれるプロシージャTForm1.Button1Clickをコードエディタに作り出す。<br />
<br />
[[Image:NeuesProjekt2.png]]<br />
<br />
<br />
アプリケーションにButton1をクリックした後に何かをさせるために、プロシージャTForm1.Button1Clickの[[Begin]]と[[End]]の間にこのようにコードを加える:<br />
<br />
<syntaxhighlight lang=pascal><br />
procedure TForm1.Button1Click(Sender: TObject);<br />
begin<br />
Caption:='My first Form'; //Form1のキャプションが変更される(フォーム冒頭のテキスト)<br />
//or<br />
Button1.Caption:='Hello'; //ボタンのキャプションが変更される(ボタンのテキストが表示される)<br />
end;<br />
</syntaxhighlight><br />
<br />
そして、{{keypress|F9}}を押し、フォームを起動させる、ボタンをクリックしたときにフォームキャプションとボタンキャプションの双方が変わることに注意すること。<br />
<br />
ちょっとした実験を行い、スタンダードコンポーネントの使い方を学んだ。始めるにあたり、以下のコンポーネントの例を試してみることを勧める:<br />
<br />
{|<br />
|-<br />
| [[TButton/ja|TButton]] || [[image:tbutton.png]]<br />
|-<br />
| [[TLabel/ja|TLabel]] || [[image:tlabel.png]]<br />
|-<br />
| [[TEdit/ja|TEdit]] || [[image:tedit.png]]<br />
|-<br />
| [[TMemo/ja|TMemo]] || [[image:tmemo.png]]<br />
|-<br />
| [[TToggleBox/ja|TToggleBox]] || [[image:ttogglebox.png]]<br />
|-<br />
| [[TCheckBox/ja|TCheckBox]] || [[image:tcheckbox.png]]<br />
|-<br />
| [[TRadioButton/ja|TRadioButton]] || [[image:tradiobutton.png]]<br />
|-<br />
| [[TListBox/ja|TListBox]] || [[image:tlistbox.png]]<br />
|-<br />
| [[TComboBox/ja|TComboBox]] || [[image:tcombobox.png]]<br />
|-<br />
| [[TScrollBar/ja|TScrollBar]] || [[image:tscrollbar.png]]<br />
|}<br />
<br />
ここにさらに役に立つ情報がある[[Lazarus Tutorial/ja|Lazarusチュートリアル]]。<br />
<br />
== 2つ目のフォームを使う ==<br />
<br />
このチュートリアルでは1つのプロジェクトで複数のフォームを使う方法を示す。この例で2つだけのフォーム、Form1(メインフォーム)とForm2が作られるが、追加のフォームについてもその仕方は同一である。<br />
<br />
クリックされると新しいフォームを開くボタンがメインフォームにある。新しいフォームはまた、クリックされるとそれ自身を閉じ、メインフォームに帰ってくるボタンを有する。<br />
もし最初のチュートリアル、 [[Form_Tutorial/ja#初めてのGUIアプリケーション | 初めてのGUIアプリケーション]]を終えているのなら、TForm1.Button1Clickプロシージャのbeginとendの間のコードを削除しておく必要がある。そうしないと、新たなプロジェクト(アプリケーション)フォームにボタンを置き、キャプション(ボタンの上の表示されるテキスト)を入力し、OnClickイベントハンドラをこのButton1に作らなければならない。<br><br />
これを行うためボタンを選択(一度クリックする)し、オブジェクトインスペクタで、プロパティ -> Caption、「Open Form2」と入力する。<br />
<br />
[[Image:ObjectInspector_ja.png]]<br />
<br />
2つ目のフォーム(Form2)をプロジェクトに加えるため、メインメニューで ファイル -> 新規フォームを実行する。Form2にボタンを置きそれにOnClickイベントを作る。このボタンのキャプションを「Close」に変更する。<br />
<br />
いま、このプロジェクトは2つのフォームを持ち、それぞれはメインメニュー、プロジェクト -> フォーム...(もしくはキーの組み合わせ{{keypress|Shift}} + {{keypress|F12}})で選択、表示できる。また別に、ソースエディタでUnitタブで選択もでき、{{keypress|F12}}でコードエディタと[[Unit]]に割り当てられたフォームデザイナとを切り替えできる。<br />
<br />
[[source code editor]]で[[Unit]] (Unit1)が割り当てられたForm1に行き[[Uses]]に節「Unit2を加える:<br />
<br />
<syntaxhighlight lang=pascal><br />
uses<br />
Classes, SysUtils, ... , Unit2; // それぞれのユニットがコンマ(,)で区切られていることと<br />
// uses 節がセミコロン(;)で終わることは重要である。<br />
</syntaxhighlight><br />
<br />
今、Unit2(即ちForm2)をUnit1から呼び出すことができる。<br />
<br />
次に、Form1に属するボタンのOnClickイベントを編集する:<br />
<br />
<syntaxhighlight lang=pascal><br />
unit Unit1;<br />
...<br />
procedure TForm1.Button1Click(Sender: TObject);<br />
begin<br />
Form2.ShowModal; //Form2を表示、フォーカスはForm2に来る。<br />
end;<br />
</syntaxhighlight><br />
<syntaxhighlight lang=pascal><br />
unit Unit2;<br />
...<br />
procedure TForm2.Button1Click(Sender: TObject);<br />
begin<br />
Close; //Form2を閉じる<br />
end; <br />
</syntaxhighlight><br />
<br />
これで、プロジェクトを起動([[Image:Start.png]] もしくは {{keypress|F9}})し、Form1のボタンをクリックすることでForm2を開くことができる。<br />
<br />
=== ShowとShowModalの違い ===<br />
<br />
''Show''および ''ShowModal''メソッドは双方ともフォームを見えるようにする。''Show''と''ShowModal''の違いを見るために:<br />
<br />
* 前の例、''Form1''[[Form Tutorial/ja#2つ目のフォームを使う|2つ目のフォームを使う]]に2番目のTButtonを加え拡張する。<br />
* ''Button1''を選択しプロパティ''Name''を ''btnShow''に、''Caption''を ''Show''に変更する。<br />
* ''Button2''を選択しプロパティ''Name'' を''btnShowModal''に、''Caption''を''ShowModal''に変更する。<br />
* ''OnClick''イベントを作る(もしくは、変更)し2つのボタンのイベントハンドラを以下のようにする:<br />
<br />
<syntaxhighlight lang=pascal><br />
procedure TForm1.btnShowClick(Sender: TObject);<br />
begin<br />
Form2.Show;<br />
ShowMessage('Form2 is opened!');<br />
end;<br />
<br />
procedure TForm1.btnShowModalClick(Sender: TObject);<br />
begin<br />
Form2.ShowModal;<br />
ShowMessage('Form2 is opened and closed again!');<br />
end;<br />
</syntaxhighlight><br />
<br />
* 起動してその差を見よう!<br />
<br />
;Show:<br />
このプロシージャはフォームを見える状態にし、呼んだコントロール(''Form1'')のコードの実行を継続する。この例ではメッセージ、([[Dialog_Examples#ShowMessage|ShowMessage]]) はほとんど''Form2''と同時に現れる。また''Form1''を呼んで使い続けることができる。例えばそれを動かしたり、''Show''ボタンを押すことができる(しかし''ShowModal''をクリックするとエラーが発生するだろう)。<br />
<br />
'''<code><myForm>.Show;</code>'''を用いる代わりに、'''<code><myForm>.Visible:=True;</code>'''を用いることもできる、''Show''メソッドは以下を行う:<br />
<br />
<syntaxhighlight lang=pascal><br />
procedure TCustomForm.Show;<br />
begin<br />
Visible := True;<br />
BringToFront;<br />
end;<br />
</syntaxhighlight><br />
<br />
'''<code><myForm>.Show;</code>'''と'''<code><myForm>.Visible:=True;</code>'''の唯一の違いは、''Show''を用いてフォームを表示すると、現在表示されているすべての他のフォームの上に表示されることである。<br />
<br />
;ShowModal:<br />
<br />
''ShowModal''は新しく開かれているフォーム(''Form2'')が閉じられるまで呼び出したコントロール(''Form1'')を停止させる。例では、''ShowModal''の直後の''ShowMessage''行は''Form2''が閉じた後にのみ実行される。フォームの呼び出しは固まってしまう;''Form1''を動かすこともそれが持つどのボタンも押すことができない。<br />
<br />
ShowModalは整数値の結果を返す関数である。[[doc:lcl/forms/tmodalresult.html|TModalResult]]を参照のこと。返された値によりどのようにフォームを閉じたかを分岐できる。<br />
<br />
== お互いを呼び出すことのできる2つのフォーム ==<br />
<br />
2番目のフォームからメインフォームを呼ぶことを避けるのは一般的に良いプログラム設計である。2番目のフォームを閉じることによって、(前の例のように)メインフォームへ戻り、メインフォームにフォーカスを返すこともより好ましい。しかしこの例が示すように、サブフォームからメインフォームを呼ぶことは可能である。<br />
<br />
Form1がForm2を呼ぶために、Unit1はそのUses節の中にUnit2を持っていなければならない。<br />
逆にForm2がForm1を呼ぶために、Unit2はそのUses節にUnit1を持っていなければならない。これはお互いのユニットが他のユニットを参照しあう、潜在的な循環ユニット参照コンパイラエラーにつながる。この例は循環ユニット参照エラーをどのように避けるかも示している。<br />
<br />
この例を設定するために、前の例([[Form Tutorial/ja#2つ目のフォームを使う|2つ目のフォームを使う]])のフォームを改造する、、もしくはそれぞれが1個のボタンを持つ新しいプロジェクトを作る。Form1.Button1のキャプションを「Open Form2」、Form2.Button1のキャプションを「Open Form1」と設定する。<br />
<br />
もし、前の例を改造するなら、Unit1のUses節から「Unit2」を除くこと。<br />
<br />
<br />
それぞれの[[Unit]]の[[Implementation]]セクションにUses節を加える。Unit1の節にUnit2を、Unit2の節にUnit1を加えると以下のようになる:<br />
<syntaxhighlight lang=pascal><br />
unit Unit1;<br />
...<br />
implementation<br />
<br />
uses<br />
Unit2; <br />
...<br />
</syntaxhighlight><br />
<syntaxhighlight lang=pascal><br />
unit Unit2;<br />
...<br />
implementation<br />
<br />
uses<br />
Unit1; <br />
...<br />
</syntaxhighlight><br />
<br />
ボタンイベントハンドラのOnClickイベント以後にあるコードを変更する:<br />
<br />
<syntaxhighlight lang=pascal><br />
unit Unit1;<br />
...<br />
procedure TForm1.Button1Click(Sender: TObject);<br />
begin<br />
Form2.Show; <br />
end; <br />
</syntaxhighlight><br />
<br />
<syntaxhighlight lang=pascal><br />
unit Unit2;<br />
...<br />
procedure TForm2.Button1Click(Sender: TObject);<br />
begin<br />
Form1.Show; <br />
end; <br />
</syntaxhighlight><br />
<br />
== 他のフォームに変数を渡す ==<br />
<br />
上記の例、[[Form Tutorial/ja#2つ目のフォームを使う|2つ目のフォームを使う]]によれば、Unit2のinterface部で[[Global_variables | グローバル変数]]を宣言することができる。これはUnit1とUnit2の双方が同じ[[Variable | 変数]]にアクセスすることを可能にする(Unit1のUses節にUnit2を置くことにより、Unit2のinterface部で宣言されたすべての変数も、Unit1で利用できるようになる)。この習慣は、どの個々の変数がスコープにあるかを記憶することが急速に困難となり、潜在的なエラーの元となるので、最小限にすべきである。[[Local_variables|ローカル変数]]を使い、[[Class]]の中の[[Object_Oriented_Programming_with_Free_Pascal_and_Lazarus#Properties| プロパティ]]を、あるいは別にクラスの中の変数として定義することがより好ましい。<br />
<br />
次のプロジェクトでは、2番目のフォームをボタンのクリックで開く。この時、メインフォームのユニットが2番目のフォームが何回表示されたかを勘定する。この2番目のフォームでボタンをクリックすることで、何回それが開かれたを見るために尋ねることができる:<br />
* 2つのフォームを持ち、それぞれボタンがあり、それらを評価するOnClickイベントがある新しいプロジェクト。<br />
* ここで、Countという名前の整数型の[[Class]] TForm2のpublic部の変数(この場合変数の悪用として定義する[[Const | 定数]])が作り出す:<br />
<br />
<syntaxhighlight lang=pascal><br />
unit Unit2;<br />
...<br />
TForm2 = class(TForm)<br />
Button1: TButton;<br />
procedure Button1Click(Sender: TObject);<br />
private<br />
{ プライベート宣言 }<br />
public<br />
{ パブリック宣言 }<br />
const Count: Integer = 0; //ここ<br />
end;<br />
</syntaxhighlight><br />
<br />
* Buttonイベントハンドラをそれに応じてカスタマイズする:<br />
<br />
<syntaxhighlight lang=pascal><br />
unit Unit1;<br />
...<br />
procedure TForm1.Button1Click(Sender: TObject);<br />
begin<br />
inc(Form2.Count); //Form2が呼ばれるたびにカウンタを1つ増やす<br />
Form2.ShowModal; <br />
end;<br />
</syntaxhighlight><br />
<br />
<syntaxhighlight lang=pascal><br />
unit Unit2;<br />
...<br />
procedure TForm2.Button1Click(Sender: TObject);<br />
begin<br />
ShowMessage('Form2 would be displayed '+IntToStr(Count)+' times');<br />
end; <br />
</syntaxhighlight><br />
<br />
このようにUnit1の中でUnit2のすべてのパブリック変数/プロパティ/関数/プロシージャ(一般的なメソッド)にアクセスできる。<br />
<br />
== 他のフォームに関する事柄 ==<br />
<br />
=== もう1つのフォームをメインフォームとして使う ===<br />
<br />
もし起動時にしばらく異なるフォームもしくは視覚的に新しいフォームを表示させたいと決めたとすると、メインメニュー、プロジェクト -> プロフェクトオプション -> フォーム...を実行できる:<br />
<br />
[[Image:ProjectOptionForms_ja.png]]<br />
<br />
また別に、メインメニュー、プロフェクト -> 表示(Lazarus 3.2ではここに表示 - Showというメニューはない) .lprファイル、Project.lpr(メインプログラムのPascalコード)から、最初に表示されるフォームを作ることができる:<br />
<br />
<syntaxhighlight lang=pascal><br />
program Project1;<br />
...<br />
Application.CreateForm(TForm2, Form2); //Form2が最初に作られ、アプリケーションが起動されるときに表示される<br />
Application.CreateForm(TForm1, Form1);<br />
</syntaxhighlight><br />
<br />
=== プログラムの終わりで形のプロパティを保存する ===<br />
<br />
* [[Remember form position and size#Using_TForm.SessionProperties and TXMLPropStorage]]<br />
<br />
== 動的にフォームを作る ==<br />
<br />
=== Lazarusによってデザインされたフォームを動的に作る === <br />
<br />
アプリケーション起動中に呼び出されるかもしれないすべてのフォームを作る必要はない。開発者によっては一般的にそれを保持せずにProject.lprから、プロジェクトに新しくフォームを挿入するときに自動的に生成されたコードを削除する。もし、いくつかのGUIを含むライブラリを書きたいとすると、フォームの動的生成を避けては通れない。<br />
<br />
例:<br />
<br />
* 2つのフォームを持つ新しいアプリケーション、Form1にはボタン(「Unit2」を加える、Uses節にUnit1)<br />
* open the Project.lpr (プロジェクト -> lprファイル (注)先にあるように現在このメニューはない、lprファイルを開きたいときは、ファイル -> 開く...から)<br />
* 「Application.CreateForm(TForm2, Form2);」行を削除<br />
* Form1、Button1のOnClickイベントに以下のコードを追加する:<br />
<br />
<syntaxhighlight lang=pascal><br />
procedure TForm1.Button1Click(Sender: TObject);<br />
begin<br />
Form2:=TForm2.Create(Nil); //Form2が生成される<br />
Form2.ShowModal; //Form2が表示される<br />
FreeAndNil(Form2); //Form2解放<br />
end;<br />
</syntaxhighlight><br />
<br />
* 単純に起動<br />
<br />
=== 新しいフォームを動的に生成する ===<br />
<br />
以下はフォームデザイナを使わずにコードで新しいフォームを生成する例を示している。<br />
<br />
この例ではボタンをクリックすることで、自身にボタンを含むもう1つのフォームが開くはずである。この2番目のボタンをクリックするとフォームを閉じると警告が出て、フォームが閉じられる。<br />
<br />
* 1つのフォームと1つのボタンを持つ新しいアプリケーションを作る<br />
* Form1、Button1のOnClickイベントに以下のコードを加える:<br />
<br />
<syntaxhighlight lang=pascal><br />
procedure TForm1.Button1Click(Sender: TObject);<br />
var<br />
MyForm: TForm;<br />
MyButton: TButton;<br />
begin<br />
MyForm:=TForm.Create(nil); <br />
MyForm.SetBounds(100, 100, 220, 150); <br />
MyForm.Caption:='My dynamic created form';<br />
<br />
MyButton:=TButton.create(MyForm); <br />
MyButton.Caption:='Close my form';<br />
MyButton.SetBounds(10, 10, 200, 30);<br />
MyButton.Parent:=MyForm;<br />
<br />
MyButton.OnClick:=@MyButtonClick; <br />
<br />
MyForm.ShowModal; <br />
<br />
FreeAndNil(MyForm); <br />
end;<br />
</syntaxhighlight><br />
<br />
{{Note|もしコンポーネントが所有者(TButton.Create(Owner: TComponent))から生成されると、それはコンポーネントを解放する責任のある所有者に属する。そのため、MyButtonはMyFormを解放することによって自動的に解放される。}}<br />
<br />
* ここでMyButton.OnClickに対するイベントハンドラ、MyButton.OnClickが生成されなければならない。これを終了させるため、class TForm1のprivateセクションに以下のプロシージャ宣言を書くこと:<br />
<br />
<syntaxhighlight lang=pascal><br />
TForm1 = class(TForm)<br />
...<br />
private<br />
{ private declarations }<br />
procedure MyButtonClick(Sender: TObject);<br />
</syntaxhighlight><br />
<br />
* {{keypress|Ctrl]}}+{{keypress|Shift}}+{{keypress|C}} (コード補完)を押し、ハンドラ実装として以下を挿入すること:<br />
<br />
<syntaxhighlight lang=pascal><br />
procedure TForm1.MyButtonClick(Sender: TObject);<br />
begin<br />
Showmessage('Attention, closing my dynamically created form!');<br />
if Sender is TButton then<br />
TForm(TButton(Sender).Parent).Close;<br />
end;<br />
</syntaxhighlight><br />
<br />
* ここでプロジェクトがコンパイルされ、実行できる。<br />
<br />
== 以下も参照のこと ==<br />
* [[LCL Tips|Tips for manual generation of controls]]<br />
* [[LCL_Tips#Creating_a_GUI_by_code|Example to create a complete GUI application by code]]<br />
* [[Testing, if form exists]]<br />
* [[Canvas draw vertical line on form/de]]<br />
* [[Drawing with canvas]] on form<br />
* [[user should not be able to close form]]<br />
* [[LCL_Tips#Creating_a_non-rectangular_window_or_control|Creating a non-rectangular window or control]]<br />
* [[Remember form position and size]]<br />
* [[Form in DLL]]</div>Aribenhttps://wiki.freepascal.org/TDBNavigator/jaTDBNavigator/ja2024-03-15T05:07:26Z<p>Ariben: to</p>
<hr />
<div>{{TDBNavigator}}<br />
<br />
{{Japanese Menu}}<br />
<br />
'''TDBNavigator''' [[image:tdbnavigator.png]]は接続されたデータベースとともに用いられるナビゲーションコントロールである。これは[[Component Palette/ja]]の[[Data Controls tab/ja]]から利用できる。<br />
<br />
使用するには、TDBNavigatorは[[TDataSource/ja]]コンポーネントにリンクされなければならない。TDataSourcesの状態によってナビゲーターのボタンは多少、影響を受ける。<br />
<br />
[[image:component-TDBNavigator.png]]<br />
<br />
== 以下も参照のこと ==<br />
* [[doc:lcl/dbctrls/tdbnavigator.html|TDBNavigator doc]]<br />
* [[TDataSource]]<br />
<br />
{{LCL Components}}</div>Aribenhttps://wiki.freepascal.org/TSQLTransaction/jaTSQLTransaction/ja2024-03-15T03:59:48Z<p>Ariben: </p>
<hr />
<div>{{TSQLTransaction}}<br />
{{Infobox databases/ja}}<br />
{{Japanese Menu}}<br />
'''TSQLTransaction''' [[image:tsqltransaction.png]]は例えば、[[TSQLConnection/ja]]といったデータベース接続と[[TSQLQuery/ja]]のような[[TDataSet/ja]]由来物を仲介する不可視のコンポーネントである。<br />
<br />
A TSQLTransactionは<tt>Commit()</tt>によって実行されるすべてのクエリ、あるいは<tt>Rollback()</tt>を用いない一連のクエリをガードする。<br />
<br />
'''SQLTransaction1'''.Database := SQLConnection1;<br />
SQLQuery1.Transaction := '''SQLTransaction1''';<br />
<br />
== Freepascal ドキュメンテーション ==<br />
* [http://www.freepascal.org/docs-html/fcl/sqldb/tsqltransaction.html TSQLTransaction doc]<br />
* [[TDataSet/ja]]<br />
{{LCL Components/ja}}</div>Aribenhttps://wiki.freepascal.org/TDBEdit/jaTDBEdit/ja2024-03-15T03:13:33Z<p>Ariben: </p>
<hr />
<div>{{TDBEdit}}<br />
{{Japanese Menu}}<br />
<br />
'''TDBEdit''' [[image:tdbedit.png]]は接続されたデータベースと用いる編集コントロールである。これは[[Component Palette/ja]]の[[Data Controls tab/ja]]にある。<br />
<br />
用いるには、TDBEditは[[TDataSource/ja]]コンポーネントにリンクされなければならない。''DataField''プロパティはデータベースの現在の行から何が表示されるのか決定する。<br />
<br />
== 以下も参照のこと ==<br />
* [[doc:lcl/dbctrls/tdbedit.html|TDBEdit doc]]<br />
* [[TDataSource/ja]]<br />
* [[TEdit/ja]]<br />
<br />
{{LCL Components/ja}}</div>Aribenhttps://wiki.freepascal.org/Database_libraries/jaDatabase libraries/ja2024-03-15T01:35:39Z<p>Ariben: /* See also */</p>
<hr />
<div>{{Database_libraries}}<br />
<br />
{| class="wikitable sortable"<br />
! Name<br />
! Developers<br />
! Platforms<br />
! License<br />
! Supported databases<br />
|-<br />
| [http://www.advantagedatabase.com/ Advantage TDataSet Descendant] || || Linux, Windows, NetWare || || Clipper, FoxPro and Visual FoxPro 9 DBF<br />
|-<br />
| [http://fblib.altervista.org/ FBLib] || Alessandro Batistiによる。現在Graeme Geldenhuysによって維持されている || Windows, Linux || LGPL || Firebird, Interbase.<br>The latest FBLib code is currently hosted in the [[tiOPF]] repository.<br />
|-<br />
| [[fcl-db]] || FPC team (コンポーネントはLazarusに含まれる) || さまざまな(DBクライアントライブラリ) || Modified LGPL (like rest of FPC FCL) || Dbase, In-memory, Interbase, Firebird, Microsoft SQL Server, MySQL, ODBC (e.g. MS Access), Oracle, Paradox, PostgreSQL, SQLite, Sybase ASE.<br />
|-<br />
| [http://sourceforge.net/projects/fibl/ FIBL] || Sergey Smirnov || || LGPL || Firebird<br />
|-<br />
| [[IBX]] || [http://www.mwasoftware.co.uk/ MWA Software] || Linux, Windows || InterBase Public License, Initial Developers Public License || Firebird<br />
|-<br />
| [http://pdo.sourceforge.net/ Pascal Data Objects (PDO)] || John Marino || Windows, Linux || LGPL || MySQL, Firebird<br />
|-<br />
| [[tiOPF]] || Peter Hinrichsen,<br>Graeme Geldenhuys || Windows, Linux || MPL, Modified LGPL || Interbase via IBX, Oracle via DOA, MySQL via ZeosLib, XML via MSDOM, XML via XMLLite, Paradox via BDE, MSAccess via ADO, MSSQLServer via ADO, FireBird via FBLib, FireBird via SqlDB, PostgreSQL via SqlDB, HTTP Proxy-Remote, Text files (CSV and TAB files) <br />
|-<br />
| [[TPSQL]] || Antonio d'Avino || || modified-LGPL || PostgreSQL<br />
|-<br />
| [http://tdbf.sourceforge.net/ TDBF] || Micha Nelissen || Supported by FPC || LGPL || dBase, FoxPro files<br />
|-<br />
| [https://github.com/hgourvest/uib Unified Interbase] || [https://github.com/hgourvest/uib Henri Gourvest] || || MPL || Interbase, Firebird<br />
|-<br />
| [[ZeosDBO|Zeoslib]] || Zeos team || || GPL, LGPL || MySQL, PostgreSQL, Interbase, Firebird, MS SQL Server, Sybase, Oracle and SQLite<br />
|-<br />
| [[ZMSQL]] || Zlatko Matic || || Modified LGPL and MPL || In-memory, flat text files<br />
|}<br />
<br />
==以下も参照のこと==<br />
<br />
* [[Databases/ja]]</div>Aribenhttps://wiki.freepascal.org/TDBListBox/jaTDBListBox/ja2024-03-15T01:25:32Z<p>Ariben: </p>
<hr />
<div>{{TDBListBox}}<br />
{{Japanese Menu}}<br />
A '''TDBListBox''' [[image:tdblistbox.png]] はユーザーがselectした結合された[[TDataSet/ja]]からスクロールできる短い文字列のリストを表示する。これは[[Component Palette/ja]]の[[Data Controls tab/ja]]から利用できる。<br />
<br />
==以下も参照のこと==<br />
* [[doc:lcl/dbctrls/tdblistbox.html|TDBListBox doc]]<br />
* [[TDBLookupListBox]]<br />
* [[TListBox]]<br />
* [[TDataSource]]<br />
<br />
{{LCL Components}}</div>Ariben