computer science - study of algorithms and data structures, including (1) their formal properties, (2) their linguistic and mechanical realizations, and (3) their applications.
ABSTRACTION: Reasoning about the essential properties of an object, ignoring unimportant details.
GENERALITY: The extent to which a device can be applied to many similar tasks rather than a few specific tasks.
data type - set of values that a given variable is permitted to take
e.g. integer - -32,768 to +32,767
abstract data type (ADT) - data type definition plus specification of the operations that are valid for the new type (ex. integer with assignment, arithmetic and comparison operators)
use ADTs like stacks, queues, trees, graphs, sets
data structure - way of representing or implementing an ADT
reduce complexity by information hiding (encapsulation or packaging)
INFORMATION HIDING / ENCAPSULATION: Embedding the details of a program element inside the element in such a way that when it is applied, its inner details do not have to be known. Ideally the inner details are so well hidden that not only are they not needed, they are not even available (usually thought of as "invisible" to the outside).
SPECIFICATION: A detailed description of the essential properties of an object. In programming, a complete description of a program unit's required behavior.
IMPLEMENTATION: An object built to satisfy a specification. In programming, a program unit written to behave as specified. Not all behavior is specified, which gives the implementor some flexibility in deciding implementation specific behavior.
INTERFACE: The way in which an object interacts with its external environment. In programming, a description of how a programming unit is invoked from its external program environment (e.g., parmeter passing conventions) along with a list of any dependencies that exist between the two (e.g., global variables used by the unit).
BLACK BOX MODEL: Viewing an object in terms of its interface, ignoring all internal details, pretending that the internal environment is co pletely hidden inside a black box. In programming, viewing a program element in terms of its interface while ignoring its inner details (e.g., local variables and algorithms).
MODULE: A separately compiled program unit that can be used to collect related constants, types, variables and subprograms in such a way that any program or module can access module elements that have been designated public, while only the source module can access module elements that have been designated private.
THE Header File: C++'S MECHANISM FOR ADTs
library module encapsulates types, variables, constants and procedures
Data Abstraction and Objects
OBJECT-ORIENTED DESIGN AND PROGRAMMING
" The future of computing is in object-oriented programming "
Nobel Laureate Kenneth Wilson
OOPs is a shift from passive data structures that are manipulated by procedures into active units that manipulate themselves (Brookshears)
" Object-oriented programming is a programming paradigm that encapsulates both data and procedures (methods) within an object. Objects are activated by messages. This paradigm emphasizes the interface between objects rather than the content of objects, encouraging the development of modular, interchangable units of code. True OO systems also support inheritance in the context of class hierarchies, enabling programmers to describe descendent objects efficiently by describing only the differences between parent and child objects. " Interface, 1990
"What makes programming object-oriented? Mainly a linking technique whereby common characteristics or traits can be 'inherited' or passed from one programming module or 'object' to another." Interface, 1990
"Object-oriented programming is hailed as the keystone to the future of computer programming. A number of reasons are often cited. the prinicpal ones are an ability to generate re-usable code--a long-held programmer's dream--and a reduction in lines of computer coding--in some cases a 50 to 75 percent savings in programming time and effort have been realized." Interface, 1990
Definition An object is a bundle of variables and behaviors. An object has a type, which is called its class. An object's class defines the particular variables that it contains and the behaviors that it can exhibit. The variables associated with a class are called instance variables and the behaviors are called methods. Methods are the processes that can be activated within an object-oriented design. Thus, methods correspond to the functions and procedures of a function-oriented design.
Definition An object-oriented design methodology has four major steps:
Problem Decomposition: natural decomposition
Formal Specifications: document with pre- and post-conditions
Functional Cohesion: automatic
Communicational cohesion - all parts of a routine are related to a common collection of data
Loosely Coupled and Explicit Interfaces: data is static and messages are passed
Information Hiding: automatic
Chapter 2 - Is This Really Programming
C++ Builder program - application framework
events (stimulus) and functions (response)
How Much Programming is there to do?
Building Your Own Components in C++ Builder (Code it once, use it forever)
BigThink versus LittleThink versus MiddleThink
Top-down design with stepwise refinement (BigThink)
Bottom-up programming with modularization (LittleThink)
C++ Builder - MiddleThink: worrying about putting components together and the edges in-between
Hints to studying C++ Builder:
Learn by doing
Don't try to be a C++ wizard (C++ Builder is a different approach to programming)
Learn one component at a time, and learn it wholly
Examine Borland's example applications
Exile the bulk of your C++ code to separate units apart from your form units
Don't try to create your own C++ Builder components before you completely understand how to use them
Use your right brain
Chapter 4 - All of Your Stuff -- And Buckets to Put It In
variables - "buckets for data"
initializing variables
literal constants vs. named constants
data types: short integer (-32768 -> 32767)
int, longint (-2147483648 -> 2147483647)
char (-128-127)
float (1.17 x 10-38 -> 3.4 x 1038) 6 significant
figures
double (2.22 x 10-308 -> 1.79 x 10308) 15 sig. fig.
long double (3.4 x 10-4932 -> 1.18 x 104932) 18 sig. fig
bool
String
arithmetic operators: +, -, *, /, %
comment delimiters //, /* */
C++ Builder still supports null terminated strings (arrays of characters) with strcpy, strlen, & strcat
bool AllDone;
AllDone = false;
AllDone = (Counter == 0);
Relational operators: =, >, <, <>, <=, >=
Simple & Compound IF statements
TFormBorderStyle Myborder;
MyBorder = bsSingle;
if (MyBorder == bsSizeable) then
See ROOTDEMO on CD
void __fastcall TForm1::FormCreate(TObject *Sender)
//procedure which fills a ListBox with a square root table}
{
int count;
float nbr;
char realText;
for (count = 1; count <= 100; count++)
{
nbr = sqrt(count);
sprintf (realText, "%3d: %14.9f", count, nbr);
ListBox1->Items->Add(realText);
}
}
Chars1D Array1D;
Array1D[4] = 'Q';
Array1D[2] = Array1D[4];
for (count = 0; count <= 11; count++)
Array1D[count] = (char)('a' + count);
typedef char Chars2D[12,4];
TStudent Student1;
Student1.ID = "12345";
Student1.GPA = 3.14;
Week 5/6 - Objects
The Great Dichotomy - code vs. data
void __fastcall TMainform::FileOpenItemClick(TObject *Sender)
{
String FileExt;
if OpenDialog->Execute()
{
FileExt = UpperCase(ExtractFileExt (OpenDialog->Filename));
if (FileExt == ".BMP") || (FileExt == ".ICO") || (FileExt == ".WMF")
CreatePictureViewer(OpenDialog->Filename);
else
CreateTextViewer(OpenDialog->Filename);
}
}
interface (.H file), implementation (.CPP unit file), includes clause
#include
#ifndef __MORTUNIT_H
void SetNewInterestRate
(
TMortgage & ThisMortgage,
float NewRate
);
void Recalc
(
TMortgage & ThisMortgage
);
void ApplyExtraPrincipal
(
TMortgage & ThisMortgage,
int PaymentNumber,
float Extra
);
void RangeExtraPrincipal
(
TMortgage & ThisMortgage,
int StartPayment,
int EndPayment,
float Extra
);
void MultipleExtraPrincipal
(
TMortgage & ThisMortgage,
int StartPayment,
float Extra
);
void RemoveExtraPrincipal
(
TMortgage & ThisMortgage,
int PaymentNumber
);
void RemoveAllExtraPrincipal
(
TMortgage & ThisMortgage
);
#endif
to call a function, use its name and parameter list:
Payments->Capacity = Periods;
for (i = 0; i <= Periods; i++)
TPayment *pmt;
String MyString ("Hello, world");
CS305 Week 7/8 - Objects (Encapsulation, Inheritance &
Polymorphism)
Encapsulation - binding code and data into a single structure
while hiding the implementation details
information hiding:
void __fastcall TMortgage::SetPeriods (int NewPeriodsValue)
int __fastcall TMortgage::GetPeriods (void)
important if nature of data may change and don't want users to
depend on a particular implementation of the data structures
MODEL DATA FIRST (Object-oriented design from week 2)
Inheritance
class TPayment : public TObject
All but TButton are "abstract" classes
Inherit everything you can.
Add or change only what you must.
Polymorphism - calls to methods of an object variable will call
code appropriate to whatever instance is actually in the variable.
An object is a specific instance of a class. A class is a collection of related information that includes both data and functions (the instructions for working with that data). The properties of C++Builder objects have default values. You can change these values at design time to modify an object to suit the needs of your project without writing code. If you want a property value to change at runtime, you need to write only a very small amount of code.
C++Builder applications are based on the property-method-event (PME) model of programming. Applications are built using discrete software components. These components have properties that define the component’s state. The properties can be changed to affect the components. The components also have built in methods, or member functions, which can be used to manipulate the component. Components trigger events when changes occur in the component. These events are passed by calling special event-handling properties set by the code using the component.
C++Builder’s Visual Component Library (VCL) now allows C++ programmers to do visually what they have traditionally done by hand coding classes or by coding using an application framework such as Microsoft Foundation Class (MFC) or ObjectWindows Library (OWL).
Most of the pieces that make up a Win32 application are encapsulated in the VCL library. These pieces include:
Because all these features are now available through the VCL, and most can be manipulated visually through the C++Builder user interface, C++ programmers no longer need to create or manipulate these objects through code. Many C++Builder applications can be created by designing the application visually using the C++Builder Form Designer and adding a few lines of code to the key component’s event handlers.
Remember this rule of thumb: use the VCL objects whenever possible and resist the urge to write new code until all other possibilities have been exhausted.
Field(field definition, instance variables) - data fields
within an object
Methods are procedures or functions belonging to a given object
which give an object behavior.
constructor is responsible for creating an instance of your
object and allocating memory or initializing any necessary
fields: Instance = ObjectType::Create(Parameters)
destructor deallocates any allocated memory and performs other
required housekeeping
Method Types
Static methods are the default and work like regular procedures
and functions. the compiler knows the address of the method and
when you call a static method, the compiler links it statically
into the executable.
Static member functions can only call other static member functions and only have access to static data. Such member functions do not have a this pointer.
Virtual methods can be overridden. The compiler builds a Virtual
Method Table (VMT) that provides a means to look up the method's
address at runtime. An object's VMT contains all of it's
ancestor's virtual method addresses as well as the one it
declares.
Overriding a Method
Class Visibility Specifiers
Use the public part to:
Declarations in the private part are restricted in their access. If you declare data members or methods to be private, they are unknown and inaccessible outside the class. Use the private part to:
To add data members or methods to a public, private, or protected section, put the data members or method declarations after the appropriate access specifier (public, private, and so on). Here is an example:
Place the code that implements the Calculate and ChangeColor methods in the .cpp part of the unit file pair.
Polymorphic Assignment
ans = (float) nbr;
Pointers and Masks: ex.
* Objects are active data.
* Objects can inherit both data and code from existing objects.
* Polymorphic assignment and execution allow you to work on
objects of different and unpredictable classes farther up the
object hierarchy, where they have a common ancestor class
containing common fields and methods.
CS305 Week 9/10
ifstream infile ("textfile.txt"); // declares stream variable and opens file
ifstream * infile; //declare a pointer to a stream variable
ifstream infile; //declare stream variable
ifstream infile;
if (!infile)
//open the stream and fill in the stats record
StatsFile.read ((char *)&StatsRecord, sizeof (StatsRecord));
StatsFile.seekp (4 * sizeof (StatsRecord)); // seek to the 5th record counting from 0
//seek to the end of the file before appending records
FileSize = StatsFile.tellg();
TColor TestColor;
TCanvas->PenPos property always starts at 0,0
void __fastcall TForm1::Button1Click (TObject *Sender)
Clearing a Canvas
TPen Object
specify Printer->PageWidth & Printer->PageHeight & Printer->Orientation
Use DBD to create a new table (Figs. 14.4 & 14.5)
PROJECT 2: Create a secondary index of AUTHOR CALL for PRACTICE.DB.
Table Component - logical representation of the database table
Write a OnCreate event handler to set up the fields in the DBGrid component
IndexName is for named secondary indexes
Allows for multiple index searches by including all indexes in the IndexFieldNames and
including them as parameters in the FindKey function.
TRY..FINALLY for Exception Protection
To insert a record, call the Table's Insert or Append method.
You can load a different query into the SQL property dynamically either with the Add method or the LoadFromFile method:
ex. SEMICONS.MAK
#include "ViewMain.h" - user defined units
#define __MORTUNIT_H
/*-------------------------------------------------*/
/* MORTUNIT */
/* By Jeff Duntemann KG7JF */
/* */
/* A mortgage calculation "engine" for C++ Builder. */
/* Written for *C++ Builder Programming Explorer* */
/* Copyright (c) 1995 The Coriolis Group, Inc. */
/* */
/* Adapted loosely from code originally published */
/* in DDJ for October 1991 -- Last Updated 2/26/95 */}
/*-------------------------------------------------- */
struct TLender
{
int LenderID;
String LenderName;
String LenderAddress;
String LenderCity;
String LenderState;
String LenderZIP;
String LenderPhone;
};
struct TPayment // One element in the amortization table.
{
int PaymentNum;
float PayPrincipal;
float PayInterest;
float PrincipalSoFar;
float InterestSoFar;
float ExtraPrincipal;
float Balance;
};
typedef TPayment PaymentArray[600];
struct TMortgage
{
TLender Lender; // Lender information on a loan
int Periods; // Number of periods in mortgage
int PeriodsPerYear; //Number of periods in a year
float Principal; //Amount of principal in cents
float Interest; //Percentage of interest per *YEAR*
float MonthlyPI; //Monthly payment in cents
PaymentArray Payments; //Array of payment records
}
void InitMortgage
(
TMortgage & ThisMortgage,
float StartPrincipal,
float StartInterest,
int StartPeriods,
int StartPeriodsPerYear
);
/*******************************************************/
/* MORTUNIT */
/* By Jeff Duntemann KG7JF */
/* */
/* A mortgage calculation "engine" for C++Builder. */
/* This is the unit- rather than object-based version */
/* Written for "The C++Builder Programming Explorer" */
/* Copyright © 1996, The Coriolis Group, Inc. */
/* Converted from the original version written for */
/* *The New Delphi 2 Programming Explorer* */
/* */
/* Adapted loosely from code originally published */
/* in DDJ for October 1991 -- Last Updated 1/9/96 */
/*-----------------------------------------------------*/
#include "MortUnit.h"
#include
static float CalcPayment
(
float Principal,
float InterestPerPeriod,
int NumberOfPeriods
)
{
float Factor;
Factor = pow ((1.0 + InterestPerPeriod), -NumberOfPeriods);
return (Principal * InterestPerPeriod)/(1.0 - Factor);
}
void InitMortgage
(
TMortgage & ThisMortgage,
float StartPrincipal,
float StartInterest,
int StartPeriods,
int StartPeriodsPerYear
)
{
// Set up all the initial state values in the TMortgage structure
ThisMortgage.Principal = StartPrincipal;
ThisMortgage.Interest = StartInterest;
ThisMortgage.Periods = StartPeriods;
ThisMortgage.PeriodsPerYear = StartPeriodsPerYear;
// and then build the mortgage table
Recalc (ThisMortgage);
}
void SetNewInterestRate
(
TMortgage & ThisMortgage,
float NewRate
)
{
ThisMortgage.Interest = NewRate;
Recalc (ThisMortgage); // Re-amortize the mortgage and rebuild the table
}
// This routine calculates the amortization table for the mortgage.
void Recalc
(
TMortgage & ThisMortgage
)
{
float RemainingPrincipal;
int PayNum;
float InterestThisPeriod;
float InterestPerPeriod;
float HypotheticalPrincipal;
InterestPerPeriod = ThisMortgage.Interest/ThisMortgage.PeriodsPerYear;
ThisMortgage.MonthlyPI =
CalcPayment (ThisMortgage.Principal,
InterestPerPeriod, ThisMortgage.Periods);
// Round the monthly to cents
ThisMortgage.MonthlyPI = floor (ThisMortgage.MonthlyPI * 100 + 0.5) / 100;
// Now generate the amortization table
RemainingPrincipal = ThisMortgage.Principal;
// Do this for each period (that is, payment) in the loan
for (PayNum = 1; PayNum <= ThisMortgage.Periods; PayNum++)
{
TPayment * pmt;
// Calculate the interest this period and round it to cents
InterestThisPeriod =
floor (RemainingPrincipal * InterestPerPeriod * 100 + 0.5) / 100;
// Store values into current payment structure in payment array
pmt = &(ThisMortgage.Payments[PayNum]);
pmt->PaymentNum = PayNum; // The payment number, from 1
if (RemainingPrincipal == 0)
{ // Loan's been paid off!!
pmt->PayInterest = 0;
pmt->PayPrincipal = 0;
pmt->Balance = 0;
}
else
{ // There's still principal to repay
HypotheticalPrincipal =
ThisMortgage.MonthlyPI - InterestThisPeriod + pmt->ExtraPrincipal;
if (HypotheticalPrincipal > RemainingPrincipal)
pmt->PayPrincipal = RemainingPrincipal;
else
pmt->PayPrincipal = HypotheticalPrincipal;
pmt->PayInterest = InterestThisPeriod;
// Update running balance
RemainingPrincipal = RemainingPrincipal - pmt->PayPrincipal;
pmt->Balance = RemainingPrincipal;
}
// Update the cumulative interest and principal fields
if (PayNum <= 1) // First payment; so cumulative values
{ // are simply the current values
pmt->PrincipalSoFar = pmt->PayPrincipal;
pmt->InterestSoFar = pmt->PayInterest;
}
else // We're not at first payment, so we must reach back to
{ // previous payment to calculate cumulative totals
pmt->PrincipalSoFar =
ThisMortgage.Payments[PayNum-1].PrincipalSoFar + pmt->PayPrincipal;
pmt->InterestSoFar =
ThisMortgage.Payments[PayNum-1].InterestSoFar + pmt->PayInterest;
}
}
}
void ApplyExtraPrincipal
(
TMortgage & ThisMortgage,
int PaymentNumber,
float Extra
)
{
ThisMortgage.Payments[PaymentNumber].ExtraPrincipal = Extra;
Recalc(ThisMortgage); //Re-amortize the mortgage and rebuild the table
}
void RemoveExtraPrincipal
(
TMortgage & ThisMortgage,
int PaymentNumber
)
{
ThisMortgage.Payments[PaymentNumber].ExtraPrincipal = 0.0;
Recalc(ThisMortgage); // Re-amortize the mortgage and rebuild the table
}
void RemoveAllExtraPrincipal
(
TMortgage & ThisMortgage
)
{
int i;
for (i = 0; i <= ThisMortgage.Periods; i++)
{
ThisMortgage.Payments[i].ExtraPrincipal = 0.0;
}
Recalc(ThisMortgage); //Re-amortize the mortgage and rebuild the table
}
void MultipleExtraPrincipal
(
TMortgage & ThisMortgage,
int StartPayment,
float Extra
)
{
RangeExtraPrincipal (ThisMortgage,
StartPayment,
ThisMortgage.Periods,
Extra);
}
void RangeExtraPrincipal
(
TMortgage & ThisMortgage,
int StartPayment,
int EndPayment,
float Extra
)
{
int i;
for (i = StartPayment; i <= EndPayment; i++)
{
ThisMortgage.Payments[i].ExtraPrincipal = Extra;
}
Recalc (ThisMortgage); // Re-amortize the mortgage & rebuild the table.
// Here, we clear out any unnecessary extra principal values
for (i = 1; i <= ThisMortgage.Periods; i++)
{
if ((ThisMortgage.Payments[i].Balance <= 0.00) ||
(ThisMortgage.Payments[i].Balance < Extra))
ThisMortgage.Payments[i].ExtraPrincipal = 0.00;
}
}The Header File
declares functions and data members for objects
InitMortgage (MyMortgage, 100000.0, 0.085, 360, 12);
Using Code and Data Stored in Units
#include <vcl\Classes.hpp>
#include "MortUnit.h"The Unit file
Implementing a Mortgage Engine
InitMortgage
Recalc
CalcPayment (note - hidden file)
Attaching a User Interface to a Unit-Based Engine
Use stringgrid (table) and button
//---------------------------------------------------------------------------
#ifndef UnitTestH
#define UnitTestH
//---------------------------------------------------------------------------
#include <vcl\Classes.hpp>
#include <vcl\Controls.hpp>
#include <vcl\StdCtrls.hpp>
#include <vcl\Forms.hpp>
#include <vcl\Grids.hpp>
#include "MortUnit.h" // our mortgage engine unit
//---------------------------------------------------------------------------
class TUnitTestForm : public TForm
{
__published: // IDE-managed Components
TStringGrid *UnitTestGrid;
TButton *Button1;
void __fastcall Button1Click(TObject *Sender);
void __fastcall FormCreate(TObject *Sender);
private: // User declarations
TMortgage Mortgage;
public: // User declarations
virtual __fastcall TUnitTestForm(TComponent* Owner);
};
//---------------------------------------------------------------------------
extern TUnitTestForm *UnitTestForm;
//---------------------------------------------------------------------------
#endif
/*
This is the unit-based version of the example program.
Updated for C++Builder on 01/01/97. Happy New Year!
Copyright © 1997 by The Coriolis Group, Inc.
*/
//---------------------------------------------------------------------------
#include
From Structures to Objects
unit - physical package existing as a disk file
object - logical package existing in computer memory
class TPayment : public TObject // One element in the amortization table
{
public:
int PaymentNum;
float PayPrincipal;
float PayInterest;
float PrincipalSoFar;
float InterestSoFar;
float ExtraPrincipal;
float Balance;
virtual __fastcall TPayment (void); //constructor
void __fastcall GetStringForm (String NumberStrings[]);
};
class TMortgage : public TObject
{
public:
TLender Lender; // Lender information on a loan
int Periods; // Number of periods in mortgage
int PeriodsPerYear; // Number of periods in a year
float Principal; // Amount of principal in cents
float Interest; // Percentage of interest per *YEAR*
float MonthlyPI; // Monthly payment in cents
TList * Payments; // List object holding payments
virtual __fastcall TMortgage
(
float StartPrincipal,
float StartInterest,
int StartPeriods,
int StartPeriodsPerYear
);
virtual __fastcall ~TMortgage (void);
void __fastcall SetNewInterestRate (float NewRate);
void __fastcall Recalc (void);
TPayment * __fastcall GetPayment (int PaymentNumber);
void __fastcall ApplyExtraPrincipal
(int PaymentNumber, float Extra);
void __fastcall RangeExtraPrincipal
(int StartPayment, int EndPayment, float Extra);
void __fastcall MultipleExtraPrincipal
(int StartPayment, float Extra);
void __fastcall RemoveExtraPrincipal (int PaymentNumber);
void __fastcall RemoveAllExtraPrincipal (void);
};
UNITS AND OBJECTS
void __fastcall TMortgage::RemoveAllExtraPrincipal (void)
{
int i;
for (i = 0; i <= Periods; i++)
{
TPayment * pmt;
pmt = reinterpret_cast<TPayment *>(Payments->Items[i]);
pmt->ExtraPrincipal = 0.0;
}
Recalc(); //Re-amortize the mortgage and rebuild the table
}
INHERITING CREATION
All VCL classes descend from TObject
Creating Objects
AClass *MyObjectInstance;
MyObjectInstance = new AClass;
__fastcall TPayment::TPayment (void) : TObject ()
{
}
// The constructor initializes the mortage object's fields
__fastcall TMortgage::TMortgage
(
float StartPrincipal,
float StartInterest,
int StartPeriods,
int StartPeriodsPerYear
) : TObject ()
{
int i;
// Set up all the initial state values in the TMortgage object
Principal = StartPrincipal;
Interest = StartInterest;
Periods = StartPeriods;
PeriodsPerYear = StartPeriodsPerYear;
Payments = new TList; // all objects must be created with new
// We configure the Payments TList to expand to the exact size we need
Payments->Capacity = Periods;
// Create and add Period empty payment objects to TList
for (i = 0; i <= Periods; i++)
{
Payments->Add (new TPayment);
}
// and then build the mortgage table
Recalc ();
}
Destroying Objects
delete MyObjectInstance;
__fastcall TMortgage::~TMortgage (void)
{
delete Payments;
}
AN OBJECT-ORIENTED MORTGAGE ENGINE
see MORTLIB.H and MORTLIB.CPP on the CDUsing the TList Object
Payments = new TList;
{
Payments->Add (new TPayment);
}
// Store values into current payment object in payments list
pmt = reinterpret_castThe String Data Type
String MyString;
MyString = "Hello, world";
String MyNumber (12.5); //creates a string and intializes it with "12.5"
Chapter 10 - Our Objects All Sublime
OOPs vs. Structured Programming
{
Periods = NewPeriodsValue;
}
{
return Periods;
}
The ability to create new objects that maintain the properties &
behaviors of ancestor objects
TObject
Methods common to all objects
TPersistent
ability to write itself to EXE file and bringitself back at runtime
TControl
ability to interact with the user
TWinControl
ability to use Windows machinery to create a window
TButtonControl
handles button-style resonses
TButton
provides "real" button features (pushing,changing surfaces)
TWinControl
TScrollingWinControl
TForm
TForm1
class TUnitTestForm : public TForm
{
__published: // IDE-managed Components
TStringGrid *UnitTestGrid;
TButton *Button1;
void __fastcall Button1Click(TObject *Sender);
void __fastcall FormCreate(TObject *Sender);
void __fastcall FormClose(TObject *Sender, TCloseAction &Action);
private: // User declarations
TMortgage * Mortgage;
public: // User declarations
virtual __fastcall TUnitTestForm(TComponent* Owner);
};
TObject
TPersistent
TPrinter
TGraphic
TCanvas
TControl
TBitmap
TControlCanvas
TWinControl
TScrollingWinControl
TButtonControl
TForm
TButton
TMyForm
Anatomy of an Object
An object is an instance of a class that wraps up data and code all into one bundle. Before OOP, code and data were treated as separate elements.
TFoo = class
static void IAmAStatic;
virtual void IAmAVirtual;
end;
A static member function of a global class has external linkage. A member of a local class has no linkage. A static member function is associated only with the class in which it is declared. Therefore, such member functions cannot be virtual.
Use the virtual keyword to allow derived classes to provide different versions of a base class function. Once you declare a function as virtual, you can redefine it in any derived class, even if the number and type of arguments are the same.
The redefined function overrides the base class function.
Object C++ methods can be overriden only if they are first
declared as virtual.
Overriding methods means extending or refining an ancestor's method, rather than replacing it. To override a method in a descendant class, redeclare the method in the derived class, ensuring that the number and type of arguments are the same. Ex.
class TFirstComponent : public TComponent
{
public:
void Move(); // regular method
virtual void Flash(); // virtual method
};
class TSecondComponent : public TFirstComponent
{
public:
void Move(); // declares new method "hiding" TFirstComponent::Move()
void Flash(); // overrides virtual TFirstComponent::Flash in TFirstComponent
};
Private and Public
When you build an application using the C++Builder environment, you are adding data members and methods to a descendant of TForm. You can also add data members and methods to a class without putting components on a form or filling in event handlers, but by modifying the class declaration directly.
There are private, protected, public, published, and automated declarations in a class. You can add new data members and methods to either the public or private part of a class. Public and private are keywords. When you add a new form to the project, C++Builder begins constructing the new form class. Each new class contains the public and private keywords that mark locations for data members and methods you want to add to the code directly. For example, note the private and public parts in this new form class declaration that so far contains no data members or methods:
class TForm1 : public TForm
{
__published: // IDE-managed Components
private: // User declarations
public: // User declarations
virtual __fastcall TForm1(TComponent* Owner);
};
class TForm1 : public TForm
{
__published: // reserved for IDE-managed Components
TEdit *Edit1;
TButton *Button1;
void __fastcall Button1Click(TObject *Sender);
private: // User declarations
int Number;
int Calculate (int X, int Y);
public: // User declarations
virtual __fastcall TForm1(TComponent* Owner);
void ChangeColor();
};
The Number data member and Calculate function are declared to be private. Only members within the class can use Number and Calculate. This restriction means that only the form class can use them.
Because the ChangeColor method is declared to be public, code in other units can use it. Such a method call from another unit must include the object name in the call:
Form1->ChangeColor;
The unit making this method call must #include Form1's Unit1 file.
The other declarations listed at the beginning of this section are discussed in further detail in the Programmer's Guide. In brief, the published declaration is reserved for the IDE -managed components and has the same scope as public. The IDE uses this section to maintain the component and event handlers for the form. Published properties display in the Object Inspector. Automated declarations cause automation type information to be generated for the method property and also have the same scope as public. This automation information makes it possible to create OLE Automation Servers. Protected declarations can only be seen by the current class or its descendants.
Polymorphism: Doing it Your Own Way
ex. Repaint method in TControl class
typecasting - technique where the compiler is forced to view a variable of one type as another type. [works if data size of both types the same]
int nbr;
float ans;
(reinterpret_cast<TControl *>(MyButton))->ShowHint = true;
Project POLYTEST.MAK (on disk)
void __fastcall TForm1::FormClick(TObject *Sender)
{
(reinterpret_cast
same procedure then copied to other objects' OnClick event handlers
Polymorphic Execution
replace statement above with
(reinterpret_cast<TControl *>(Sender)->Repaint();
POLYMORPHISM AND THE GRAND DESIGN
Chapter 11 - Files and File Types
Opening and Closing Files
Opening Streams
infile = new ifstream ("textfile.txt"); // create the stream and open the file
infile.open ("textfile.txt"); // open file
infile.open ("textfile.txt");
if (infile.fail ())
{
// open failed. display error message and return
}
// open successful. continue processing
{
// open failed. display error message and return
}
What Happens When You Open a File?
use a second parameter for open --
enum open_mode {
app, //Append data--always write at end of file.
ate, // Seek to end of file upon original open.
in, // Open for input (default for ifstream).
out, // Open for output (default for ofstream).
binary, // Open file in binary mode.
trunc, // discard content if file exists (default if out is specified and not app or ate
nocreate, // if file does not exist, open fails
noreplace // if file exists, open for output fails unless ate or app
};
Closing Streams
infile.close();
Text Files
sequential
Writing Text files
outfile << 'c';
if a new object is defined, you will need to overload the << operator
outfile << "Hello, " << Name << ". How are you today?" << endl;Formatting Output
outfile << setw(10) << Number1 << setw(10) << Number2 << endl;
setw left-justifies numbers and right-justifies strings; In order for strings to be left-justifed, you need to add:
outfile.setf(ios::left, ios::adjustfield);
Reading Text Files
infile >> Number1;
infile >> Number1 >> Number2 >> Number3;
infile.getline (str, 80);
Storing Binary Data
//statistics record for each one-hour period
struct AlarmStatsRecord
{
char Day[4];
char Time[6];
int NumberOfSignals;
int OperatorSignals;
int AlarmSignals;
int Troublesignals;
};
Writing and Reading Records
AlarmStatsRecord StatsRecord;
fstream StatsFile;
StatsFile.write ((char *)&StatsRecord, sizeof (StatsRecord));Detecting End Of File
for streams, use eof:
while (!infile.eof ())
{
infile.get (c);
outfile.put(c);
}
The File Pointer and Record Numbers
Moving and Examining The File Pointer
StatsFile.seekg (4 * sizeof (StatsRecord)); // seek to the 5th record counting from 0
StatsFile.read ((char *)&StatsRecord, sizeof (StatsRecord)); // and read the record
StatsFile.read ((char *)&StatsRecord, sizeof (StatsRecord)); // and read the record
StatsRecord.NumberOfSignals = 100;
StatsFile.seekp (-sizeof (StatsRecord), ios:cur); // move file pointer back 1
StatsFile.write ((char *)&StatsRecord, sizeof (StatsRecord)); // and write the record
StatsFile.seekp (0, ios::end);Chapter 12 - Points of Light, Spots on Paper
canvas of type TCanvas
Integer X, Y;
{
Canvas->Pixels[X,Y] = clWhite;
TestColor = Canvas->Pixels[X,Y];
{
Canvas->MoveTo(0,0);
Canvas->LineTo(ClientWidth, ClientHeight);
Canvas->MoveTo(ClientWidth, 0);
Canvas->LineTo(0, ClientHeight)
}
Refresh();
Pen.Color
Pen.Width
Pen.Style (psSolid, psDot, psClear, ...)
Simple Figures
Bounding Rectangles: FIGMAKER.CPP
void __fastcall TForm1::FormPainter (TObject *Sender)
{
Width = 490;
Height = 310;
Canvas->Rectangle (10, 10, 170, 80);
Canvas->Rectangle (10, 100, 170, 170);
Canvas->Ellipse(10, 100, 170, 170);
Canvas->Ellipse(10, 190, 170, 260);
Canvas->Rectangle (200, 10, 370, 80);
Canvas->RoundRect (200, 10, 370, 80, 20, 20);
Canvas->RoundRect (200, 10, 370, 170, 20, 20);
Canvas->Rectangle (400, 10, 470, 80);
Canvas->Ellipse(400, 10, 470, 80);
Canvas->Ellipse(400, 100, 470, 170);
Canvas->RoundRect (200, 190, 370, 260, 50, 20);
}
Polylines and Polygons
Open Array Parameters
void __fastcall TForm1->FormPaint (TObject *Sender)
{
Canvas->Brush->Color = clYellow;
Canvas->Polygon( OPENARRAY (Point(150,20), Point(260,100),
Point(220,220), Point(80,220),Point(40,100)));
Canvas->Polyline(OPENARRAY(Point(110,160), Point(110,100),
Point(150,160), Point(190,100), Point(190,160)));
}
Printing Graphics
#include Printer; declares TPrinter
BeginDoc
:
EndDoc
specify printer using PrinterDialogSetup1->Execute() dialog
try..catch And Printing
see PTEST.MAK on CD-ROM
to print multiple pages, use Printer->NewPage
PROJECT - SpiroMania
SPINNER.H
//---------------------------------------------------------------------------
#ifndef spinnerH
#define spinnerH
void SpinWheels(TCanvas * TargetCanvas,
int A, int B, int D,
int CenterX, int CenterY,
TColor DrawColor);
//---------------------------------------------------------------------------
#endif
SPINNER.CPP
//---------------------------------------------------------------------------
#include <vcl\vcl.h>
#pragma hdrstop
#include <math.h>
#include "spinner.h"
//---------------------------------------------------------------------------
// SpiroMania
// SPINNER.CPP : Cycloid Curve Generator
// By Jeff Duntemann KG7JF
//
// The cycloid curve generator shown here generates
// patterns similarly to the Kenner SpiroGraph toy.
// Written for *The New Delphi 2 Programming Explorer*
// Converted to C++ for *The C++Builder Programming Explorer*
// Copyright (c) 1996,1997 The Coriolis Group, Inc.
// Last Updated 1/13/97
//---------------------------------------------------------------------------
static int HighestCommonFactor (int a, int b)
{
int i, j, hcf;
// Euclid's algorithm for finding the HCF
// of two integers A and B.
if (a < b)
{
hcf = a;
i = b;
}
else
{
hcf = b;
i = a;
}
do
{
j = i % hcf;
if (j != 0)
{
i = hcf;
hcf = j;
}
} while (j != 0);
return hcf;
}
void SpinWheels(TCanvas * TargetCanvas,
int a, int b, int d,
int CenterX, int CenterY,
TColor DrawColor)
{
int rab, Lines, i;
float Alpha, Beta, ADif, AoverB;
float xpt, ypt; // line endpoint coordinates
rab = a-b;
Alpha = 0.0;
// The constants 100 and 200 here control the smoothness of
// the displayed or printed curve. The larger value must be
// twice the value that divides PI. Larger values make for
// smoother curves but longer draw times since there are
// more line segments in the drawn curve.
ADif = M_PI/100.0;
AoverB = ((float)a)/b;
Lines = 200 * (b/HighestCommonFactor(a,b));
TargetCanvas->Pen->Color = DrawColor;
TargetCanvas->MoveTo((rab+d+CenterX+0.5),CenterY);
for (i = 1; i <= Lines; i++)
{
Alpha = Alpha + ADif;
Beta = Alpha * AoverB;
xpt = rab*cos (Alpha) + d*cos(Beta);
ypt = rab*sin (Alpha) - d*sin(Beta);
TargetCanvas->LineTo(xpt+CenterX+0.5, ypt+CenterY+0.5);
}
}
SPINFORM.H
//---------------------------------------------------------------------------
#ifndef spinformH
#define spinformH
//---------------------------------------------------------------------------
#include <vcl\Classes.hpp>
#include <vcl\Controls.hpp>
#include <vcl\StdCtrls.hpp>
#include <vcl\Forms.hpp>
#include <vcl\ExtCtrls.hpp>
#include <vcl\Dialogs.hpp>
#include "sampreg.h"
//---------------------------------------------------------------------------
class TForm1 : public TForm
{
__published: // IDE-managed Components
TPanel *ButtonPanel;
TButton *SpinButton;
TButton *PrintButton;
TButton *ClearButton;
TButton *PickPrinterButton;
TButton *QuitButton;
TLabel *Label1;
TLabel *Label2;
TLabel *Label3;
TPrinterSetupDialog *PrinterSetupDialog1;
TSpinEdit *SpinA;
TSpinEdit *SpinB;
TSpinEdit *SpinD;
TColorGrid *ColorGrid1;
void __fastcall QuitButtonClick(TObject *Sender);
void __fastcall SpinButtonClick(TObject *Sender);
void __fastcall ClearButtonClick(TObject *Sender);
void __fastcall PrintButtonClick(TObject *Sender);
void __fastcall PickPrinterButtonClick(TObject *Sender);
void __fastcall FormCreate(TObject *Sender);
void __fastcall FormPaint(TObject *Sender);
private: // User declarations
public: // User declarations
virtual __fastcall TForm1(TComponent* Owner);
};
//---------------------------------------------------------------------------
extern TForm1 *Form1;
//---------------------------------------------------------------------------
#endif
SPINNER.CPP
//---------------------------------------------------------------------------
// SpiroMania
// SPINFORM.PAS : Main Form Unit
// By Jeff Duntemann KG7JF
//
// The main form unit for a cycloid curve generator
// functionally similar to the Kenner Spirograph toy.
// Written for *The New Delphi 2 Programming Explorer*
// Converted to C++ for *The C++Builder Programming Explorer*
// Copyright (c) 1996,1997 The Coriolis Group, Inc.
// Last Updated 1/13/97
//---------------------------------------------------------------------------
#include
Printing Text
Canvas->TextOut( X, Y, SomeText);
MyCanvas->Font->Name = "Courier New";
Style, Color, Size
DRAWING AND REDRAWING
All text and graphics must be redrawn whenever a form is
covered/uncovered or minimized/maximized
Use the OnPaint event FormPaint
CS350 Week 11/12
Chapter 14 - Tables on the Record
bits -> bytes(characters) -> fields -> records -> files ->
databases
A Network DBMS Example: 1-many; set; schema
uses objects and messages to accommodate types of data and provide for data
handling
DATABASE DESIGN CONSIDERATIONS
logical database design - way user views data
physical database design - actual structure of database
data dictionary
schema- complete description of content and structure of database
subschema - each user's view of the database
Different Database Formats
Microsoft's ODBC (Open Database Connectivity) - Access
Borland's IDAPI - Paradox, dBase
DATABASE DESKTOP
DBD - can load, edit & restructure tables created for use with C++ Builder
cannot print, output reporting, edit memo fields or BLOBs (Binary Large Objects)
PROJECT 1: Use DBD to look at the AUTHORS.DB table; check out the structure of the
table
Create a copy of AUTHORS.DB called PRACTICE.DB and save it on your disk. Make sure to copy and rename all files that begin with AUTHORS.
FIELD NAMES
Key Fields
SECONDARY INDEXES
C++ Builder'S DATABASE MACHINERY
Data access components - Table, DataSource, Query...
Data aware components - DBEdit, DBText, DBMemo, DBGrid, ...
DataSource Component - interface between Table component and data aware
components (contains event that records when a record has changed in the Table)
TFieldList Component - "list" of Field Objects in a Table component
Setting Up for Data Access
PROGRAMMATIC DATABASE ACCESS
Use DBNavigator to browse through a Table
Accessing Fields:
AuthorTable->Fields[0]->DisplayLabel = 'ID'; (uses offset)
AuthorTable->FieldByName('Author ID')->DisplayLabel = 'ID'; (uses name of field's
column in the database table)
Inspecting Fields:
double-click the Table Component brings up a Field Editor and puts a Field Object
into the Object Inspector
PROJECT 3: Create a project SEEKTEST.DPR with a form that allows searching the
AUTHORS.DB table by name or key.
void __fastcall TForm1::FormCreate(TObject *Sender)
{
/*
You can access fields by their index into the fields list.
That's what I'm doing here, just to demonstrate it:
*/
AuthorTable->Fields[0]->DisplayLabel = "ID";
// In most cases, it makes more sense to access fields by name:
AuthorTable->FieldByName("AUTHOR ID")->DisplayWidth = 4;
AuthorTable->FieldByName("AUTHOR ID")->ReadOnly = True;
AuthorTable->FieldByName("AUTHOR LAST NAME")->DisplayLabel = "LAST NAME";
AuthorTable->FieldByName("AUTHOR LAST NAME")->DisplayWidth = 12;
AuthorTable->FieldByName("AUTHOR FIRST NAME")->DisplayLabel = "FIRST NAME";
AuthorTable->FieldByName("AUTHOR FIRST NAME")->DisplayWidth = 10;
AuthorTable->FieldByName("AUTHOR CALL")->DisplayLabel = "CALL";
AuthorTable->FieldByName("AUTHOR CALL")->DisplayWidth = 10;
AuthorTable->FieldByName("BIRTH YEAR")->Visible = False;
AuthorTable->FieldByName("DEATH YEAR")->Visible = False;
}
SEARCHING A TABLE
(make sure that the field used in the search is a key field or a secondary index)
GOTO METHOD
void __fastcall TForm1::SeekButtonClick(TObject *Sender)
{
CallLabel->Caption = "";
AuthorTable->IndexName = "LAST NAME INDEX";
AuthorTable->SetKey ();
AuthorTable->FieldByName("AUTHOR LAST NAME")->AsString = EntryEdit->Text;
if (AuthorTable->GotoKey ())
{
StatusLabel->Caption = "Entry Found!";
CallLabel->Caption = AuthorTable->FieldByName("AUTHOR CALL")->Text;
}
else
{
StatusLabel->Caption = "Entry Not Found!";
}
}
Searching on a Key Field
void __fastcall TForm1::KeySearchButtonClick(TObject *Sender)
{
CallLabel->Caption = "";
AuthorTable->IndexFieldNames = "AUTHOR ID";
AuthorTable->SetKey ();
AuthorTable->FieldByName ("AUTHOR ID")->AsString = EntryEdit->Text;
if (AuthorTable->GotoKey ())
{
StatusLabel->Caption = "Entry Found!";
CallLabel->Caption = AuthorTable->FieldByName ("AUTHOR CALL")->Text;
}
else
{
StatusLabel->Caption = "Entry Not Found!";
}
}
IndexFieldNames is for names of fields
Using Find for Searches
void __fastcall TForm1::FindCallButtonClick(TObject *Sender)
{
String SeekValue;
AuthorTable->IndexFieldNames = "AUTHOR CALL";
SeekValue = EntryEdit->Text;
if (AuthorTable->FindKey (OPENARRAY (TVarRec, (SeekValue))))
{
StatusLabel->Caption = "Entry Found";
}
else
{
StatusLabel->Caption = "Entry Not Found";
}
}
InExact Searches with GotoNearest and FindNearest
void __fastcall TForm1::FindNearestButtonClick(TObject *Sender)
{
AuthorTable->IndexName = "LAST NAME INDEX";
AuthorTable->SetKey ();
AuthorTable->FieldByName ("AUTHOR LAST NAME")->AsString = EntryEdit->Text;
AuthorTable->GotoNearest ();
CallLabel->Caption = AuthorTable->FieldByName ("AUTHOR CALL")->Text;
}
CHANGING DATA IN EXISTING RECORDS
ex. CASETEST.MAK
SomeTable->DisableControls(); // turn off display of data during update
SomeTable->First(); // start at top of table
while (!SomeTable->Eof)
{
{read a value from a Field into a temporary variable}
{make some change to the variable}
SomeTable->Edit; {Put Table in Edit mode}
{Write the changed value back into the field}
SomeTable->Post(); {Write changes to Table}
SomeTable->Next(); {Move down to next record}
}
SomeTable->EnableControls(); {Turn display of data back on again}
Try block of statements contain code subject to exceptions
Finally block of statements must be executed even if there is an exception
try
{
SomeTable->DisableControls(); { turn off display of data during update}
SomeTable->First(); { start at top of table}
while (!SomeTable->Eof)
{
{read a value from a Field into a temporary variable}
{make some change to the variable}
SomeTable->Edit(); {Put Table in Edit mode}
{Write the changed value back into the field}
SomeTable->Post(); {Write changes to Table}
SomeTable->Next(); {Move down to next record}
}
}
catch (...)
{
SomeTable->EnableControls(); {Turn display of data back on again}
}
SomeTable->EnableControls(); {Turn display of data back on again}
//---------------------------------------------------------------------------
#include
INSERTING AND DELETING RECORDS
To delete a record, position the pointer at the record to be deleted and call the Table's
Delete method. [Good habit to include a confirmation message box for the user]
Piecemeal Insertion
DeviceTable->Insert();
DeviceTable->FieldByName('DEVICE NAME')->AsString = "12AD6";
DeviceTable->FieldByName('DEVICE DESCRIPTION')->AsString =
"12V Space charge pentagrid converter";
DeviceTable->Post();
Inserting a Record with a Single Statement
InsertRecord(OPENARRAY(TVarRec, (NULL, NULL, "12V Space charge pentagrid converter")));
//---------------------------------------------------------------------------
#include
WHAT'S LEFT
Queries, SQL, Interbase, bookmarks, ODBC
CS350 Week 13/14
Chapter 16 - SQL As API
Application Programming Interface
Application Programming Interface (API) - group of function calls (typically into Window's code libraries called Dynamic Link Libraries) that serve a common purpose
Dividing the Controller From the Controlled
client/server - separates the database from the applications
BDE (Borland Database Engine) - suite of DLLs that supports "local" database applications
SQL FROM A HEIGHT
SQL command - typically a query:
SELECT LAST_NAME FROM CUST_TABLE WHERE LAST_ORDER_DATE > 1/1/97
DROP TABLE "TEMPDATA.DB"
SQL queries usually result in result set
SQL and the TQuery Component
Local SQL is handled through a TQEURY Component
requires a TDataSource Component
TQUERY returns a result set which typically includes a subset of records and often a subset of fields
The SQL Property
SQL Property of TQuery is of type TStrings and is used to hold the SQL query
UPDATE SEMINAME
SET DEV_TYPE = :dType,
DEV_PKG = :dPkg,
DEV_DESCRIP = :dDescrip,
STOCK_LEVEL = :dLevel,
SORT_STRING = :dSort
WHERE DEV_NAME = dName
Query1->SQL->Add("SELECT * FROM SEMINAME");
Query1->SQL->LoadFromFile("INSERT.DOC");
/*
SQL Demonstration Application
By Jeff Duntemann KG7JF
FOR: The New Delphi Programming Explorer
(C) 1996 by The Coriolis group, Inc.
Converted to C++ for *The C++Builder Programming Explorer*
Last Modified 1/20/97
*/
#include <vcl\vcl.h>
#pragma hdrstop
#include "semiform.h"
//---------------------------------------------------------------------------
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
}
//---------------------------------------------------------------------------
int MaxRecordNum;
String DeriveSortString (String DeviceName)
{
int i, ResultIndex;
String Result;
/*
We work from the end of the string forward, copying numeric
characters to the sort string until we encounter an alpha.
First, fill the function's result variable with zeroes:
*/
Result = "000000000000";
ResultIndex = Result.Length () - 1;
if (DeviceName.Length () < 1)
{
return Result; // Quit on null name
}
// Result now contains 12 characters of '0'
// Next, trim non-numerics from trailing end of name:
i = DeviceName.Length () - 1;
while (!isdigit (DeviceName[i]))
{
DeviceName.Delete (i, 1);
i--;
}
// Now, copy numeric chars to Result as they're encountered:
for (i = DeviceName.Length() - 1; i >= 0; i--)
{
if (isdigit (DeviceName[i]))
{
Result[ResultIndex] = DeviceName[i];
ResultIndex--;
}
else
{
break; // first alpha we find ends the loop
}
}
return Result;
}
void __fastcall TForm1::ClearAllEntryFields (void)
{
NameField->Text = "";
PackageField->Text = "";
StockField->Text = "";
TypesGroup->ItemIndex = 0;
DescriptionField->Text = "";
SortStringField->Text = "";
}
void __fastcall TForm1::QuitButtonClick(TObject *Sender)
{
Close ();
}
//---------------------------------------------------------------------
void __fastcall TForm1::AddButtonClick(TObject *Sender)
{
if (NameField->Text.Length () == 0)
{
ShowMessage ("You haven't entered a device name!");
}
else
{
SemiQuery1->Close ();
SemiQuery1->SQL->Clear ();
SemiQuery1->SQL->LoadFromFile("INSERT.SQL");
SemiQuery1->Prepare ();
SemiQuery1->ParamByName("dID")->AsInteger = MaxRecordNum + 1;
SemiQuery1->ParamByName("dName")->AsString = NameField->Text;
SemiQuery1->ParamByName("dType")->AsString =
TypesGroup->Items->Strings[TypesGroup->ItemIndex];
SemiQuery1->ParamByName("dPkg")->AsString = PackageField->Text;
SemiQuery1->ParamByName("dDescrip")->AsString = DescriptionField->Text;
SemiQuery1->ParamByName("dLevel")->AsInteger = StrToInt(StockField->Text);
SemiQuery1->ParamByName("dSort")->AsString = SortStringField->Text;
SemiQuery1->ExecSQL ();
SemiQuery1->Close ();
MaxRecordNum = MaxRecordNum + 1;
MaxRecLabel->Caption = IntToStr(MaxRecordNum);
ClearAllEntryFields ();
UniqueLabel->Caption = "";
DupeLabel->Caption = "";
}
}
//---------------------------------------------------------------------
void __fastcall TForm1::FormCreate(TObject *Sender)
{
// Always begin execution on Add Device page:
TabbedNotebook1->PageIndex = 0;
SemiQuery1->Close ();
SemiQuery1->SQL->Clear ();
SemiQuery1->SQL->Add("SELECT MAX(DEV_ID) FROM SEMINAME");
SemiQuery1->Open ();
MaxRecordNum = SemiQuery1->Fields[0]->AsInteger;
MaxRecLabel->Caption = SemiQuery1->Fields[0]->AsString;
SemiQuery1->Close ();
SemiQuery1->SQL->Clear ();
SemiQuery1->SQL->Add("SELECT * FROM SEMINAME");
SemiQuery1->Open ();
ClearAllEntryFields ();
}
//---------------------------------------------------------------------
void __fastcall TForm1::CloneButtonClick(TObject *Sender)
{
SemiQuery1->Close ();
SemiQuery1->SQL->Clear ();
// The result set is the entire table:
SemiQuery1->SQL->Add("SELECT * FROM SEMINAME");
SemiQuery1->Open (); // Make the query and thus create the result set
// We can now navigate the result set as though it were a TTable:
SemiQuery1->Last ();
// Data is retrieved from the fields just as with TTable:
NameField->Text = SemiQuery1->FieldByName("DEV_NAME")->AsString;
PackageField->Text = SemiQuery1->FieldByName("DEV_PKG")->AsString;
StockField->Text = SemiQuery1->FieldByName("STOCK_LEVEL")->AsString;
DescriptionField->Text = SemiQuery1->FieldByName("DEV_DESCRIP")->AsString;
SemiQuery1->Close ();
}
//---------------------------------------------------------------------
void __fastcall TForm1::ClearButtonClick(TObject *Sender)
{
ClearAllEntryFields ();
}
//---------------------------------------------------------------------
void __fastcall TForm1::OpenAllInOrder (void)
{
SemiQuery1->Close ();
SemiQuery1->SQL->Clear ();
SemiQuery1->SQL->Add("SELECT * FROM SEMINAME ORDER BY SORT_STRING ASC");
SemiQuery1->Open ();
SemiQuery1->FieldByName("DEV_ID")->Visible = False;
SemiQuery1->FieldByName("SORT_STRING")->Visible = False;
SemiQuery1->FieldByName("DEV_NAME")->DisplayLabel = "Name";
SemiQuery1->FieldByName("DEV_NAME")->DisplayWidth = 8;
SemiQuery1->FieldByName("DEV_TYPE")->DisplayLabel = "Type";
SemiQuery1->FieldByName("DEV_PKG")->DisplayLabel = "Package";
SemiQuery1->FieldByName("DEV_DESCRIP")->DisplayLabel = "Description";
SemiQuery1->FieldByName("DEV_DESCRIP")->DisplayWidth = 33;
SemiQuery1->FieldByName("STOCK_LEVEL")->DisplayLabel = "Stock";
SemiQuery1->FieldByName("STOCK_LEVEL")->DisplayWidth = 5;
}
//---------------------------------------------------------------------
void __fastcall TForm1::TabbedNotebook1Change(TObject *Sender, int NewTab,
bool &AllowChange)
{
switch (NewTab)
{
case 2 : // Drop Device Page
OpenAllInOrder (); // Open the full table in SORT_STRING order
SemiQuery1->FieldByName("DEV_TYPE")->Visible = false;
SemiQuery1->FieldByName("DEV_PKG")->Visible = false;
// This simply displays the name of the item currently
// at the query cursor, in the DeleteLookupField:
DeleteLookupLabel->Caption =
SemiQuery1->FieldByName("DEV_NAME")->AsString;
break;
case 3 : // View By Name Page
OpenAllInOrder (); // Open the full table in SORT_STRING order
break;
case 4 : // View by Types Page
ShowByTypesGroup->ItemIndex = -1;
ShowByTypesCountLabel->Caption = "";
OpenAllInOrder ();
SemiQuery1->FieldByName("DEV_TYPE")->Visible = false;
SemiQuery1->FieldByName("DEV_ID")->Visible = false;
SemiQuery1->FieldByName("DEV_PKG")->Visible = false;
SemiQuery1->FieldByName("SORT_STRING")->Visible = false;
SemiQuery1->FieldByName("DEV_NAME")->DisplayWidth = 9;
SemiQuery1->FieldByName("DEV_DESCRIP")->DisplayWidth = 40;
SemiQuery1->FieldByName("STOCK_LEVEL")->DisplayWidth = 5;
ShowByTypesCountCaptionLabel->Caption =
"All devices in the table are shown->";
break;
}
}
//---------------------------------------------------------------------
void __fastcall TForm1::NameFieldExit(TObject *Sender)
{
SortStringField->Text = DeriveSortString(NameField->Text);
}
void __fastcall TForm1::SemiSourceDataChange(TObject *Sender,
TField *Field)
{
if (TabbedNotebook1->PageIndex == 2)
{
DeleteLookupLabel->Caption =
SemiQuery1->FieldByName("DEV_NAME")->AsString;
}
}
//---------------------------------------------------------------------
void __fastcall TForm1::DeleteButtonClick(TObject *Sender)
{
String DeviceToDelete;
bool AllowChangeValue;
/*
When the user clicks the Delete button, we save the name
of the device at the current query cursor, then confirm:
*/
DeviceToDelete = SemiQuery1->FieldByName("DEV_NAME")->AsString;
if (DeviceToDelete.Length () == 0)
{
ShowMessage ("No device selected");
}
else
{
Set<TMsgDlgBtn, 0, 8> tempSet;
tempSet << mbYesNoCancel;
if (MessageDlg ("Delete "+DeviceToDelete+"?",
mtConfirmation, tempSet, 0) == mrYes)
{
SemiQuery1->Close ();
SemiQuery1->SQL->Clear ();
SemiQuery1->SQL->Add ("DELETE FROM SEMINAME WHERE DEV_NAME = :dName");
SemiQuery1->Prepare ();
// Here we plug in DeviceToDelete for ":dName":
SemiQuery1->ParamByName("dName")->AsString = DeviceToDelete;
SemiQuery1->ExecSQL (); // Do the DELETE Query!
SemiQuery1->Close (); // This task is done; close the TQuery
}
}
DeleteLookupField-> Text = "";
/*
This is a sneaky way to re-use the code that opens the query
on the full table, by triggering the event that normally
happens only when you change the tabbed notebook page
*/
TabbedNotebook1Change (DeleteButton,2,AllowChangeValue);
}
//---------------------------------------------------------------------
void __fastcall TForm1::DeleteLookupFieldChange(TObject *Sender)
{
SemiQuery1->Close ();
SemiQuery1->SQL->Clear ();
SemiQuery1->SQL->Add("SELECT * FROM SEMINAME WHERE DEV_NAME LIKE :dName");
SemiQuery1->Prepare ();
SemiQuery1->ParamByName("dName")->AsString = DeleteLookupField->Text+"%";
SemiQuery1->Open ();
}
void __fastcall TForm1::ChangeLookupFieldChange(TObject *Sender)
{
String TypeString;
SemiQuery1->Close ();
SemiQuery1->SQL->Clear ();
SemiQuery1->SQL->Add("SELECT * FROM SEMINAME WHERE DEV_NAME LIKE :dName");
SemiQuery1->Prepare ();
SemiQuery1->ParamByName("dName")->AsString = ChangeLookupField->Text + "%";
SemiQuery1->Open ();
// Display number of records in result set
MatchCountLabel->Caption = IntToStr(SemiQuery1->RecordCount);
SemiQuery1->First (); // Make sure you"re on first record in result set
// Put the existing record values into the change entry fields
ChangeNameLabel->Caption = SemiQuery1->FieldByName("DEV_NAME")->AsString;
ChangeSortStringField->Text = SemiQuery1->FieldByName("SORT_STRING")->AsString;
ChangePackageField->Text = SemiQuery1->FieldByName("DEV_PKG")->AsString;
ChangeStockField->Text = SemiQuery1->FieldByName("STOCK_LEVEL")->AsString;
ChangeDescriptionField->Text = SemiQuery1->FieldByName("DEV_DESCRIP")->AsString;
TypeString = SemiQuery1->FieldByName("DEV_TYPE")->AsString;
ChangeTypesGroup->ItemIndex =
ChangeTypesGroup->Items->IndexOf(TypeString);
}
//---------------------------------------------------------------------
void __fastcall TForm1::ClearChangesButtonClick(TObject *Sender)
{
if (SemiQuery1->Active)
{ // Only if a result set is open!
ChangeSortStringField->Text = SemiQuery1->FieldByName("SORT_STRING")->AsString;
ChangePackageField->Text = SemiQuery1->FieldByName("DEV_PKG")->AsString;
ChangeStockField->Text = SemiQuery1->FieldByName("STOCK_LEVEL")->AsString;
ChangeDescriptionField->Text = SemiQuery1->FieldByName("dev_descrip")->AsString;
}
}
//---------------------------------------------------------------------
void __fastcall TForm1::SaveChangesButtonClick(TObject *Sender)
{
SemiQuery1->Close ();
SemiQuery1->SQL->Clear ();
SemiQuery1->SQL->LoadFromFile("UPDATE.SQL");
SemiQuery1->Prepare ();
SemiQuery1->ParamByName("dName")->AsString = ChangeNameLabel->Caption;
if (ChangeTypesGroup->ItemIndex >= 0)
SemiQuery1->ParamByName("dType")->AsString =
ChangeTypesGroup->Items->Strings[ChangeTypesGroup->ItemIndex];
else
SemiQuery1->ParamByName("dType")->AsString = "";
SemiQuery1->ParamByName("dPkg")->AsString = ChangePackageField->Text;
SemiQuery1->ParamByName("dDescrip")->AsString = ChangeDescriptionField->Text;
SemiQuery1->ParamByName("dLevel")->AsInteger = StrToInt(ChangeStockField->Text);
SemiQuery1->ParamByName("dSort")->AsString = ChangeSortStringField->Text;
SemiQuery1->ExecSQL (); // Used for queries that don"t return result sets!
SemiQuery1->Close ();
// Clear out all values from the change edit fields:
ChangeNameLabel->Caption = "";
ChangeSortStringField->Text = "";
ChangePackageField->Text = "";
ChangeStockField->Text = "";
ChangeDescriptionField->Text = "";
ChangeTypesGroup->ItemIndex = -1;
}
//---------------------------------------------------------------------
void __fastcall TForm1::NameFieldChange(TObject *Sender)
{
SemiQuery1->Close ();
SemiQuery1->SQL->Clear ();
SemiQuery1->SQL->Add("SELECT * FROM SEMINAME WHERE DEV_NAME LIKE :dName");
SemiQuery1->Prepare ();
SemiQuery1->ParamByName("dName")->AsString = NameField->Text + "%";
SemiQuery1->Open ();
if (SemiQuery1->RecordCount > 0)
{
DupeLabel->Caption = "Dupe!";
UniqueLabel->Caption = "";
}
else
{
DupeLabel->Caption = "";
UniqueLabel->Caption = "Unique!";
}
}
//---------------------------------------------------------------------
void __fastcall TForm1::ShowByTypesGroupClick(TObject *Sender)
{
SemiQuery1->Close ();
SemiQuery1->SQL->Clear ();
SemiQuery1->SQL->Add("SELECT * FROM SEMINAME WHERE DEV_TYPE LIKE :dType");
SemiQuery1->Prepare ();
SemiQuery1->ParamByName("dType")->AsString =
ShowByTypesGroup->Items->Strings[ShowByTypesGroup->ItemIndex];
SemiQuery1->Open ();
SemiQuery1->FieldByName("DEV_TYPE")->Visible = False;
SemiQuery1->FieldByName("DEV_ID")->Visible = False;
SemiQuery1->FieldByName("DEV_PKG")->Visible = False;
SemiQuery1->FieldByName("SORT_STRING")->Visible = False;
SemiQuery1->FieldByName("DEV_NAME")->DisplayLabel = "Name";
SemiQuery1->FieldByName("DEV_NAME")->DisplayWidth = 9;
SemiQuery1->FieldByName("STOCK_LEVEL")->DisplayLabel = "Stock";
SemiQuery1->FieldByName("STOCK_LEVEL")->DisplayWidth = 5;
SemiQuery1->FieldByName("DEV_DESCRIP")->DisplayLabel = "Description";
SemiQuery1->FieldByName("DEV_DESCRIP")->DisplayWidth = 40;
ShowByTypesCountCaptionLabel->Caption =
"such devices are in the table.";
ShowByTypesCountLabel->Caption = IntToStr(SemiQuery1->RecordCount);
}
//---------------------------------------------------------------------
void __fastcall TForm1::ShowAllButtonClick(TObject *Sender)
{
bool AllowChangeValue;
// Fake a page change to Page 4 to show all records
TabbedNotebook1Change (ShowAllButton,4,AllowChangeValue);
}
SQL'S DATA DEFINITION LANGUAGE
Creating a Table with SQL
CREATE TABLE SEMINAME
(
DEV_ID INTEGER,
DEV_NAME CHAR(12),
DEV_TYPE CHAR(10),
DEV_PKG CHAR(12),
DEV_DESCRIP CHAR(50),
PRIMARY KEY(DEV_ID)
)
Executing SQL Queries
void __fastcall TForm1::CreateButtonClick (TObject *Sender)
{
UtilityQuery->Close();
UtilityQuery->SQL->Clear ();
UtilityQuery->SQL->LoadFromFile("CREATE.SQL");
UtilityQuery->ExecSQL ();
UtilityQuery->Close();
Adding a Column to a Table With SQL
void __fastcall TForm1::AddColumnButtonClick (TObject *Sender)
{
UtilityQuery->Close();
UtilityQuery->SQL->Clear ();
UtilityQuery->SQL->Add("ALTER TABLE SEMINAME");
UtilityQuery->SQL->Add("ADD STOCK_LEVEL INTEGER");
UtilityQuery->ExecSQL ();
UtilityQuery->Close();
Creating Indexes With SQL
UtilityQuery->Close();
UtilityQuery->SQL->Clear ();
UtilityQuery->SQL->Add("CREATE INDEX NAMEIDX ON SEMINAME DEV_NAME");
UtilityQuery->ExecSQL ();
UtilityQuery->Close();
Adding Records with Insert
INSERT INTO SEMINAME(DEV_ID,
DEV_TYPE,
DEV_NAME,
DEV_PKG,
DEV_DESCRIP,
STOCK_LEVEL,
SORT_STRING)
VALUES(:dID, :dName,:dType,:dPkg,:dDescrip,:dLevel,:dSort)
Static and Dynamic SQL Queries
The VALUES clause contains a list of parameters that are identified by a colon
Parameter Assignment and Substitution
each SQL parameter is also a legal C++ identifier and can be assigned values using the ParamByName method
void __fastcall TForm1::AddButtonClick(TObject *Sender)
{
if (NameField->Text.Length () == 0)
{
ShowMessage ("You haven't entered a device name!");
}
else
{
SemiQuery1->Close ();
SemiQuery1->SQL->Clear ();
SemiQuery1->SQL->LoadFromFile("INSERT.SQL");
SemiQuery1->Prepare ();
SemiQuery1->ParamByName("dID")->AsInteger = MaxRecordNum + 1;
SemiQuery1->ParamByName("dName")->AsString = NameField->Text;
SemiQuery1->ParamByName("dType")->AsString =
TypesGroup->Items->Strings[TypesGroup->ItemIndex];
SemiQuery1->ParamByName("dPkg")->AsString = PackageField->Text;
SemiQuery1->ParamByName("dDescrip")->AsString = DescriptionField->Text;
SemiQuery1->ParamByName("dLevel")->AsInteger = StrToInt(StockField->Text);
SemiQuery1->ParamByName("dSort")->AsString = SortStringField->Text;
SemiQuery1->ExecSQL ();
SemiQuery1->Close ();
MaxRecordNum = MaxRecordNum + 1;
MaxRecLabel->Caption = IntToStr(MaxRecordNum);
ClearAllEntryFields ();
UniqueLabel->Caption = "";
DupeLabel->Caption = "";
}
}
The Prepare Method
Prepare method forces the SQL query text to the database engine for precompilation
Chapter 18 - Database Odds 'N' Ends
SQL's DISTINCT Qualifier
- see DISTINCT.MAK
THE DBLISTBOX and DBCOMBOBOX COMPONENTS
- see LOOKUP.MAK
problems with DBLookups
- see ARTENTRY.MAK