Solved

Cannot display Russian text within TMemo

Posted on 2006-11-25
23
3,366 Views
Last Modified: 2008-01-09
Hi, wonder if anyone can help here.

I have an application which has cause to read russian text from an Access database and display it in a TMemo.

I can successfully paste the Russian text into the database, but it always displays as question marks (Ie: настольный displays as ???????????).

Also, when I paste the text into the Lines property of the TMemo component at design time, it pastes in okay, but as soon as I close the Lines input box, it again displays as question marks.

I have set the TMemo Font.Charset property to RUSSIAN_CHARSET and installed a Cyrillic font and set the Font.Name property to that font.

I am probably missing something really simple, but it's driving me nuts, and doing a Google on it brings back many entries where the response is 'you need to use a cyrillic font'.  As far as I can see, I have done that, but it just ain't working for me.

Hope somebody can help.  This is really holding me back, so I am giving loads of points away for a swift resolution to the issue.

Thanks in advance.

Justin

0
Comment
Question by:JustinByrom
  • 9
  • 8
  • 3
  • +1
23 Comments
 
LVL 1

Author Comment

by:JustinByrom
ID: 18011229
Yep, well there we go with the first problem.  Pasted in the proper russian text which displayed okay when writing my question, but I now see it has given the literal character values instead.
0
 
LVL 28

Accepted Solution

by:
ciuly earned 500 total points
ID: 18011236
the other "page" of this issue is unicode: if you are dealing with unicode instead (and from "(Ie: настольный " I see unicode) that means you need some unicode enabled controls. Delphi standard component do not know to display unicode.
a nice set of unicode components are tntware: http://www.tntware.com/delphicontrols/unicode/
0
 
LVL 9

Expert Comment

by:alkisg
ID: 18011508
I agree with cuily on tnt unicode controls, I've been using them for 4 years now, they 're great.

Another way:
If you're only interested in Russian and English characters, you may keep using ANSI controls.
You'll have to "say" to Delphi & to Windows that you want to use the Russian encoding.
To inform Windows:
  if Win32PlatformIsUnicode then
    SetThreadLocale($00000408); //408 is for Greek, you need the Russian LCID
To inform Delphi:
  SetMultiByteConversionCodePage(1253); //1253 is for Greek, you need the Russian ANSI codepage

This way implicit AnsiString <=> WideString conversions will use the Russian codepage, so everything in your app will work OK with no other modifications.
It won't work for the Delphi IDE though, you'll have to use either D2005+ OR tnt unicode controls OR make a component and call SetMultiByteConversionCodePage in its initialization section (the IDE calls it automatically).

SetMultiByteConversionCodePage is not available in D7-, see my QC13292 in borland quality central for a workaround:
http://qc.borland.com/wc/qcmain.aspx?d=13292
0
 
LVL 9

Expert Comment

by:alkisg
ID: 18011523
BTW, if you change your WINDOWS locale to Russian (start->run->intl.cpl => advanced), EVERYTHING will work OK without ANY code modifications (even the IDE).
0
 
LVL 1

Author Comment

by:JustinByrom
ID: 18011650
I think cuily has put me on the right lines.

I am having issues with bringing data through from Access, but at least I can get Russian text displayed now.

I will post back shortly ...
0
 
LVL 1

Author Comment

by:JustinByrom
ID: 18011668
I am querying using a tquery created at runtime and a datasource component now linked to the TNTDBGrid component.  It still displays the text as question marks.

Is this the SQL causing a problem?
0
 
LVL 1

Author Comment

by:JustinByrom
ID: 18011676
For the record, I am developing in Delphi 7 Pro, using ADO data access controls connecting to an Access database.

The software will need to accept and display Russian text in a potentially non-Russian Windows locale, so a solution purely code-based would be of huge benefit.

It looks like the TNT components will work, except for the data retrieval issue described above.

Cheers
0
 
LVL 28

Expert Comment

by:ciuly
ID: 18011681
is the data in the access db saved from (the old) code? if so, then I would consider re-saving it ;)
0
 
LVL 9

Expert Comment

by:alkisg
ID: 18011686
It could be SQL causing the problem, or you may be using a String or AnsiString somewhere.
Example:
var
  w: WideString;
  s: String;
begin
  w := 'Some Russian characters that came from the database OK';
  s := w;
  MyMemo.Text := s;
  ...

This will result to question marks.

1) What version of Delphi you're using?
2) Do you want to make this a unicode app, or is it for Russians only?
Because if it is, then just change your Windows locale to Russian. Everything will work OK with no problems.
0
 
LVL 9

Expert Comment

by:alkisg
ID: 18011709
Experts-exchange could surely use a "you got beaten to posting" feature!!! :-)

If your target clients only use 2000, XP or Vista (no 98/Me), then there are Windows API functions to temporarily switch the locale to Russian ONLY FOR YOUR APP.

To debug your app, you may use MessageBoxW. It displays unicode characters, so you can find out at which point the conversion fails.
Don't rely on the IDE debugging features, D7 is an ANSI application, it'll show '???' instead of unicode chars.
0
 
LVL 1

Author Comment

by:JustinByrom
ID: 18011717
great.  that was gonna be my next question!!!

I'll give that a go ...
0
Maximize Your Threat Intelligence Reporting

Reporting is one of the most important and least talked about aspects of a world-class threat intelligence program. Here’s how to do it right.

 
LVL 1

Author Comment

by:JustinByrom
ID: 18011846
Okay, I am using fieldbyname ('...').asstring, and have changed the asstring to asvariant, but no joy.  it is bringing it back as ???? still.

Let me expand what I have ...

Access database with a table containing field 'RussianText' as type Memo with Unicode compression enabled.

I perform an sql query on the table which brings it back.

I access the field with FieldByName ('RussianText').AsVariant.

The value is held by a widestring variable, which is then displayed on the form in a TNT label.

Still nothing but ?????s ...
0
 
LVL 9

Expert Comment

by:alkisg
ID: 18012479
I've never used ADO, and I rarely use databases in Delphi, so I won't be much of help here. Wait for cuily! :-)

What descenant of TField is used? TWideStringField? TVariantField? Check it with classname...
Because if TStringField is used, the unicode data is lost, you'll have to change it somehow to either TWideStringFiled or TVariantField.
0
 
LVL 28

Expert Comment

by:ciuly
ID: 18012638
my DB expertise is also not very helpfull. first because I never used unicode in my applications (except some winapi) and second because my DB operations were basic. but I also suspect something along the line alkisg suggest: if the server sends it correctly then it's lost. I don't think I got a reply about my query if the data from the DB was saved from the old app or not. basically, if the data in the DB IS or not unicode. not the data type, but the data itself.
best thing is to save some data with the tnt components and retrieve it back. make sure evertyhing in the line is unicode and if you still get teh same ???? then we're kind of lost.

just an idea: post another 20 points pointer question to this one with the title saying something like "Problems saving/loading unicode strings to DB using tntware". then someone who knows about this will notice it and reply ;)
after all, it could be some known issue somewhere and only experience can help there.
0
 
LVL 9

Expert Comment

by:alkisg
ID: 18012712
Is there a connection string somewhere, or a way to tell the db to send you the data using either utf-8 or russian encoding? This could easily solve the problem...
0
 
LVL 1

Author Comment

by:JustinByrom
ID: 18012910
Guys, some more food for thought there.

The data in the database was pasted straight into it.  That part is static data, but the main application will need to add and amend data dynamically, so I will also need to ensure that it is saved in unicode format.

The TField descendant is TVariantField.

I will do some more work on it tomorrow, as it's done my head in today, but thanks for the help so far.  I have definitely made progress.
0
 
LVL 9

Expert Comment

by:alkisg
ID: 18013751
As I read in http://www.marcocantu.com/md2005/UpdateDelphi2006_ch13.html unicode support for databases is only available for D2006... If you could upgrade to D2006 you'd make your life easier!

I can't help more for the db-related part of the problem, but if you don't find a solution, tell me to describe you how to make a SetMultiByteConversionCodePage function for D7. This will at least enable you to use English + Russian characters, but no true unicode though (only on the fetching/sending layer where the problem is located, data on the db WILL be true unicode).
0
 
LVL 1

Author Comment

by:JustinByrom
ID: 18014917
Alkisg,

Yes, that looks like the way I will go.

My client has said that we can do a stand alone Russian version if required, but I will be upgrading Delphi next year.

I bought Delphi 8 for .NET, but the .NET side was very wobbly and many of my colleagues have returned to Delphi 7 until Borland get their .NET version stable and working well.
0
 
LVL 9

Expert Comment

by:alkisg
ID: 18015051
Sorry, my English is not that good, what did you mean by
> Yes, that looks like the way I will go.
?

Will you wait until you upgrade to D2006 OR you'll make a Russian-only version for the time being?

If it is the second one, you'll need to do the following:
1) Temporarily switch your locale to Russian:
Start->run->intl.cpl->advanced->select Russian as the locale for non-unicode programs. Reboot.
2) Verify that your app fetches and stores Russian characters correctly with no code modifications.

3) Give me some feedback, so that we can continue with the next steps! :-)

4) Implementation of SetMultiByteConversionCodePage for D7. This is a little tricky, if D7 Pro comes with VCL source code, it'll be easier to do it by calculating the address of System.DefaultSystemCodePage, otherwise it'll need hooking of GetACP, but the hook should be installed before System.pas is initialized, so it'll probably need an external .dll or wrapper program...
5) A call to SetThreadLocale(*RUSSIAN LC_ID*);

The result will be an app capable to run on a NT/2000/XP/Vista system with ANY locale and store Russian characters. On Windows 9x, the system locale will have to be Russian (9x don't support unicode).
0
 
LVL 9

Expert Comment

by:bernani
ID: 18015706

Hi,

Using the tntCompo's can you permit to do the job provided you have installed the Russian language at install time. By default, it's not installed.
 
Verify in your database file (file.mdb) that for the text fields you need to display in the Delphi memo, the property Unicode compression (or sth like this) is set to true.

Here is a demo code written in D5 (not unicode compliant) to add cyrillic text in a little database. The demo is an adress book displaying all the entry in a tntDBGrid connected with a msAcces database.

// the main form connect only the database and display the data to the user in the DBGrid.

unit AdCyrilTest;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ComCtrls, DB, ADODB, Grids, DBGrids, StdCtrls, Mask, DBCtrls,
  ExtCtrls, TntDBCtrls, TntDBGrids, TntStdCtrls;

type
  TTestAdoCyrillic = class(TForm)
    PageControl1: TPageControl;
    TabSheet1: TTabSheet;
    TabSheet2: TTabSheet;
    ADOConnection1: TADOConnection;
    ADOTable1: TADOTable;
    ADOTable1Nom: TWideStringField;
    ADOTable1Adr: TWideStringField;
    ADOTable1Cp: TWideStringField;
    ADOTable1Ville: TWideStringField;
    ADOTable1Tel: TWideStringField;
    DataSource1: TDataSource;
    Label1: TLabel;
    Label2: TLabel;
    DBEdit2: TDBEdit;
    Label3: TLabel;
    DBEdit3: TDBEdit;
    Label4: TLabel;
    DBEdit4: TDBEdit;
    Label5: TLabel;
    DBEdit5: TDBEdit;
    DBNavigator1: TDBNavigator;
    DBEdit1: TTntDBEdit;
    DBGrid1: TTntDBGrid;
    DBMemo1: TTntDBMemo;
    procedure FormCreate(Sender: TObject);

  private
    { Déclarations privées }
  public
    { Déclarations publiques }
  end;

var
  TestAdoCyrillic: TTestAdoCyrillic;

implementation

{$R *.dfm}

procedure TTestAdoCyrillic.FormCreate(Sender: TObject);
var
  BDPath, StringConnect : string;
begin
BDPath := 'C:\Delphi5\Projects\DelphiADO\Client.mdb';
StringConnect:= 'Provider=Microsoft.Jet.OLEDB.4.0;' +
            'User ID=Admin;' +
            'Data Source=' + BDPath + ';' +
            'Mode=Share Deny None;Extended Properties="";' +
            'Jet OLEDB:System database="";Jet OLEDB:Registry Path="";' +
            'Jet OLEDB:Database Password="";Jet OLEDB:Engine Type=5;' +
            'Jet OLEDB:Database Locking Mode=1;' +
            'Jet OLEDB:Global Partial Bulk Ops=2;' +
            'Jet OLEDB:Global Bulk Transactions=1;' +
            'Jet OLEDB:New Database Password="";' +
            'Jet OLEDB:Create System Database=False;' +
            'Jet OLEDB:Encrypt Database=False;' +
            'Jet OLEDB:Don''t Copy Locale on Compact=False;' +
            'Jet OLEDB:Compact Without Replica Repair=False;' +
            'Jet OLEDB:SFP=False';
ADOConnection1.ConnectionString := StringConnect ;
ADOTable1.Active := True;
end;

end.


//The dfm of the form. One property need to be set to display correctly the data
//      object DBGrid1: TTntDBGrid
// ...
//   Font.Charset = RUSSIAN_CHARSET
//
//If you don't set the charst to Russian, the data from you DB won't display correctly.
// That's all.


object TestAdoCyrillic: TTestAdoCyrillic
  Left = 327
  Top = 177
  BorderStyle = bsSingle
  Caption = 'Test Ado Cyrillic'
  ClientHeight = 326
  ClientWidth = 466
  Color = clBtnFace
  Font.Charset = DEFAULT_CHARSET
  Font.Color = clWindowText
  Font.Height = -11
  Font.Name = 'MS Sans Serif'
  Font.Style = []
  OldCreateOrder = False
  OnCreate = FormCreate
  PixelsPerInch = 96
  TextHeight = 13
  object PageControl1: TPageControl
    Left = 8
    Top = 8
    Width = 449
    Height = 313
    ActivePage = TabSheet1
    TabOrder = 0
    object TabSheet1: TTabSheet
      Caption = '&Liste'
      object DBGrid1: TTntDBGrid
        Left = 16
        Top = 24
        Width = 409
        Height = 97
        DataSource = DataSource1
        Font.Charset = RUSSIAN_CHARSET
        Font.Color = clWindowText
        Font.Height = -11
        Font.Name = 'MS Sans Serif'
        Font.Style = []
        ParentFont = False
        TabOrder = 0
        TitleFont.Charset = DEFAULT_CHARSET
        TitleFont.Color = clWindowText
        TitleFont.Height = -11
        TitleFont.Name = 'MS Sans Serif'
        TitleFont.Style = []
      end
      object DBMemo1: TTntDBMemo
        Left = 16
        Top = 136
        Width = 409
        Height = 129
        DataField = 'Nom'
        DataSource = DataSource1
        ScrollBars = ssVertical
        TabOrder = 1
      end
    end
    object TabSheet2: TTabSheet
      Caption = '&Fiche'
      ImageIndex = 1
      object Label1: TLabel
        Left = 8
        Top = 8
        Width = 31
        Height = 13
        Caption = 'Field 1'
      end
      object Label2: TLabel
        Left = 8
        Top = 48
        Width = 31
        Height = 13
        Caption = 'Field 2'
        FocusControl = DBEdit2
      end
      object Label3: TLabel
        Left = 8
        Top = 88
        Width = 31
        Height = 13
        Caption = 'Field 3'
        FocusControl = DBEdit3
      end
      object Label4: TLabel
        Left = 8
        Top = 128
        Width = 31
        Height = 13
        Caption = 'Field 4'
        FocusControl = DBEdit4
      end
      object Label5: TLabel
        Left = 8
        Top = 168
        Width = 31
        Height = 13
        Caption = 'Field 5'
        FocusControl = DBEdit5
      end
      object DBEdit2: TDBEdit
        Left = 8
        Top = 64
        Width = 400
        Height = 21
        DataField = 'Adr'
        DataSource = DataSource1
        TabOrder = 0
      end
      object DBEdit3: TDBEdit
        Left = 8
        Top = 104
        Width = 69
        Height = 21
        DataField = 'Cp'
        DataSource = DataSource1
        TabOrder = 1
      end
      object DBEdit4: TDBEdit
        Left = 8
        Top = 144
        Width = 300
        Height = 21
        DataField = 'Ville'
        DataSource = DataSource1
        TabOrder = 2
      end
      object DBEdit5: TDBEdit
        Left = 8
        Top = 184
        Width = 200
        Height = 21
        DataField = 'Tel'
        DataSource = DataSource1
        TabOrder = 3
      end
      object DBNavigator1: TDBNavigator
        Left = 216
        Top = 232
        Width = 196
        Height = 25
        DataSource = DataSource1
        VisibleButtons = [nbFirst, nbPrior, nbNext, nbLast, nbInsert, nbDelete, nbPost]
        TabOrder = 4
      end
      object DBEdit1: TTntDBEdit
        Left = 8
        Top = 24
        Width = 401
        Height = 21
        DataField = 'Nom'
        DataSource = DataSource1
        TabOrder = 5
      end
    end
  end
  object ADOConnection1: TADOConnection
    LoginPrompt = False
    Mode = cmShareDenyNone
    Provider = 'Microsoft.Jet.OLEDB.4.0'
    Left = 344
  end
  object ADOTable1: TADOTable
    Connection = ADOConnection1
    CursorType = ctStatic
    IndexFieldNames = 'Nom'
    TableName = 'Client'
    Left = 376
    object ADOTable1Nom: TWideStringField
      DisplayWidth = 29
      FieldName = 'Nom'
      Size = 50
    end
    object ADOTable1Adr: TWideStringField
      DisplayWidth = 39
      FieldName = 'Adr'
      Size = 200
    end
    object ADOTable1Cp: TWideStringField
      DisplayWidth = 6
      FieldName = 'Cp'
      Size = 5
    end
    object ADOTable1Ville: TWideStringField
      DisplayWidth = 19
      FieldName = 'Ville'
      Size = 50
    end
    object ADOTable1Tel: TWideStringField
      DisplayWidth = 19
      FieldName = 'Tel'
      Size = 25
    end
  end
  object DataSource1: TDataSource
    DataSet = ADOTable1
    Left = 408
  end
end


If you are able to input cyrillic, compile demotest above and type some text in the fields 1, 2, 3 .... save and switch to other tab to see the display of you data in the DBGrid and DBMemo (all tntCompos).

In other words, you need set the font.charset to russian for the components which are retrieving their data from the database.

I've tested with D5 and Access 2000. It's fully functionnal provided the use of tntCompo's.

Hope this help.

0
 
LVL 9

Expert Comment

by:bernani
ID: 18015735
Hi,

Maybe you can also read my answer (it was for Outlook but apply also to Access).

http://www.experts-exchange.com/Applications/MS_Office/Outlook/Q_22065317.html

and eventually read (it for Chinese but can be adapted to any language):

http://www.experts-exchange.com/Programming/Programming_Languages/Delphi/Q_21800480.html

0
 
LVL 9

Expert Comment

by:bernani
ID: 18015806
Hi,

Forgot to say:

In the demo unit above, you'll see that I didn't change the Field 2, Field 3, Field 4 & Field 5: these are standard Delphi TDBEdit.

Only Field 1 is a TTntDBEdit.

If you try to input cyrillic text in the first field, it's correctly displayed and saved in the database.

The others fields will display strange chars or ????.

Replace all the standard dbEdits by TntDBEdit and all will be able to display cyrillic (do the same for the labels if neded).

0
 
LVL 1

Author Comment

by:JustinByrom
ID: 18017785
Bernani,

Will try that this morning.

Looks hopeful though.

Cheers
0

Featured Post

How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

Join & Write a Comment

Suggested Solutions

Introduction The parallel port is a very commonly known port, it was widely used to connect a printer to the PC, if you look at the back of your computer, for those who don't have newer computers, there will be a port with 25 pins and a small print…
In my programming career I have only very rarely run into situations where operator overloading would be of any use in my work.  Normally those situations involved math with either overly large numbers (hundreds of thousands of digits or accuracy re…
Sending a Secure fax is easy with eFax Corporate (http://www.enterprise.efax.com). First, Just open a new email message.  In the To field, type your recipient's fax number @efaxsend.com. You can even send a secure international fax — just include t…
Access reports are powerful and flexible. Learn how to create a query and then a grouped report using the wizard. Modify the report design after the wizard is done to make it look better. There will be another video to explain how to put the final p…

746 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

9 Experts available now in Live!

Get 1:1 Help Now