QAbstractItemModel을 적용하고 있는 View에 보여지는 폰트 변경하는 방법입니다.
일단 예시로 QAbstractItemModel을 상속받고 있는 QFileSystemModel을 상속받는 다른 클래스를 만들어 줍니다. 그리고 data 함수와 headerData 함수를 오버라이딩 합니다.
class MyFileSystem : public QFileSystemModel
{
QVariant data ( const QModelIndex& index, int role ) const;
QVariand headerData (int section, Qt::Orientation orientation, int role ) const;
...;
};
data 함수를 통해 본문의 폰트를 수정, headerData 함수를 통해 가장 상단 header의 폰트를 수정할 수 있습니다.
QFont font;
QVariant data( const QModelIndex& index, int role )
{
if ( role == Qt::FontRole ) {
return font;
}
return QFileSystemModel::data(index, role);
}
QVariand headerData(int section, Qt::Orientation orientation, int role )
{
if ( role == Qt::FontRole ) {
return font;
}
return QFileSystemModel::headerData(section, orientation, role);
}
기존 dart 문법에서 var 자료형을 쓰면 처음 초기화 한 형태에 맞는 자료형을 갖게 됩니다. 하지만 한번 자료형이 정해진 var 변수에 다른 형태의 자료형을 그냥 대입하려 하면 문제가 생기는데 dynamic을 사용하면 대입할 때 마다 값에 맞는 자료형으로 바뀌게 됩니다.
Nullable, Non-Nullable, Null 인식 연산자
NULL이 될수 있는지 없는지 명시해줄 때 사용합니다.
null 인식 연산자(??=)의 경우 값에 null이 들어있을 경우에만 해당 값을 대입합니다.
const, final
두 키워드 모두 값의 불변을 위한 키워드로 사용합니다.
두 키워드의 차이점은 DateTime.now 같이 유동적으로 코드가 실행되는 순간 결정되는 값에는 const를 사용할 수 없습니다. final은 빌드 시 값을 몰라도 되지만 const는 빌드 시 값을 알아야 하기 때문에 사용이 불가능 합니다.
그리고 이 키워드 사용시 var 없이도 알아서 자료형을 잡아줍니다. (dynamic이 아니므로 다른 자료형의 값을 넣을 수 없습니다.)
Named Paramter
함수에 인자를 넘길 때 인자를 명시하면서 넘겨주는 방식입니다.
Arrow
함수에서 반환되는 값을 간단히 표현하기 위해 => 연산자를 사용합니다.
위에 작성한 간단한 설명은 제가 잘 몰랐던 문법이라 정리해 두었습니다. 다른 기초 문법의 경우 아래 유튜브 영상을 참고해주시기 바랍니다.
이제 입력 값을 통해 FontSize를 변경하기 위해 Button onPressd 시 TextEditingController 값을 파싱합니다. 그 후 SetState를 호출하면서 파싱된 값을 Size 변수에 넘기고 Size의 값은 Button의 TextStyle에 넘겨주게 됩니다.
다음으로 전달되는 위젯 클래스 MyApp입니다. MyApp은 StatelessWidget이라는 클래스를 상속받았습니다. StatelessWidget을 상속받은 위젯은 변화가 없는 즉 Run 이후 한번 로딩되면 바뀔일이 없는 위젯이 상속받아 사용합니다. 이 StatelessWidget은 build를 한번 호출해 기본 UI를 미리 구축해 놓습니다. 이제 StatelessWidget을 상속받은 MyApp도 build를 재정의하여 MyApp만의 화면을 build하여 MaterialApp을 리턴합니다.
class MyApp extends StatelessWidget {
const MyApp({super.key});
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo', // 앱 이름
theme: ThemeData(
primarySwatch: Colors.blue, // 테마 색깔
),
home: const MyHomePage(title: 'Flutter Demo Home Page'), // 앱 실행시 첫 실행할 위젯 지정
);
}
}
다음으로 MyApp에서 지정한 첫 실행에 세팅된 MyHomePage 클래스입니다. 이 클래스는 위 클래스와 다르게 StatefulWidget을 상속받았습니다. StatelessWidget과 다르게 화면에 갱신이 필요한 위젯(클래스)는 이 클래스를 상속받습니다. StatefulWidget은 먼저 State를 생성하기 위해 createState를 호출하는데 이때 State 객체를 생성합니다. createState() 옆에 =>는 return 이라고 생각하시면 됩니다.
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key, required this.title});
final String title;
@override
State<MyHomePage> createState() => _MyHomePageState();
}
마지막으로 생성한 State에 대한 설명입니다. 아래 build는 위 StatelessWidget과 같이 Widget을 생성해 반환하여 화면에 그려줍니다. 가장 처음에 있는 counter 변수는 언더바가 가장 앞에 적혀있는데 이는 현재 dart 파일에서만 사용한다는 의미입니다. incrementCounter 함수도 내부 함수이며 구현에 setState를 통해 위젯을 갱신합니다.
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Text(
'You have pushed the button this many times:',
),
Text(
'$_counter',
style: Theme.of(context).textTheme.headline4,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: const Icon(Icons.add),
), // This trailing comma makes auto-formatting nicer for build methods.
);
}
}
build에서 Scaffold라는 것을 return 하는데 기본 어플의 뼈대라고 생각하면 편할거 같습니다. 기본적으로 appbar, body,bottomNavigationbar 등이 있고 상황에 따라 원하는 구조를 추가할 수 있고 Scafforld 내에서 [ctrl] + [space]를 통해 옵션들을 확인할 수 있습니다.
body에 Center 함수로 화면 가운데 위치시키면서 child 옵션으로 Column을 그 안에 Children을 통해 Text 위젯들을 넣었습니다. 이처럼 하위에 위젯을 놓을 때 하나를 놓기 위해선 child, 여러개를 놓기 위해서는 children을 호출합니다.
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Text(
'You have pushed the button this many times:',
),
Text(
'$_counter',
style: Theme.of(context).textTheme.headline4,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: const Icon(Icons.add),
), // This trailing comma makes auto-formatting nicer for build methods.
);
마지막으로 floatingActionButton에 있는 onPressed는 클릭하였을 때 incrementCounter 함수를 호출해주고 그 함수는 위에서 setState를 통해 count 개수를 늘리며 화면을 갱신해주고 있습니다.
다트 언어에서 비동기 처리를 지원합니다. 비동기 처리는 어떤 호출이 끝나기를 마냥 기다리는 것이 아닌 일단 호출 후 다른 작업 후 추후에 처리를 해주게 됩니다. 이 비동기 처리는 파일 IO, 데이터베이스 처리, 네트워크와 같이 언제 끝날 지 모르는 작업에 유용하게 사용됩니다.
다트에서 비동기 처리를 위해 사용되는 예약어는 async, await, Future을 통해 진행됩니다. 설명에 앞서 간단한 예제를 보여드리겠습니다.
void main() {
print('Hello World!');
PrintValue();
print('Main End');
}
Future PrintValue() async {
print('PrintValue Start');
var value = await Getvalue();
print(value);
print('PrintValue End');
}
int Getvalue() {
return 1;
}
비동기 처리에 대한 개념 없이 봤을 때 예상되는 호출 결과는
Hello World!
PrintValue Start
1
PrintValue End
Main End
가 될 것입니다. 하지만 실제 실행 결과를 보시면 아래와 같습니다.
PrintValue 함수에서 await가 붙은 함수 다음 동작을 기다리지 않고 Main End부터 실행합니다. 그 이후 Getvalue의 결과를 출력하고 마지막으로 PrintValue End를 출력합니다.
이 결과는 future async await로 인해 비동기로 처리가 되는데 PrintValue 함수 뒤에 붙은 async로 PrintValue 함수를 비동기 함수로 만들겠으며 await가 붙은 GetValue 함수를 비동기 처리를 하겠다는 의미입니다. 그렇기 때문에 PrintValue 함수 안의 GetValue 다음 행동은 GetValue가 마무리 될 때 까지 기다렸다 실행히 되고 PrintValue 이후는 그대로 진행이 되는 것입니다.
위 구성에서 await를 사용하기 위해서 Future는 생략해도 가능하지만 async를 생략하면 에러가 발생합니다.
await의 반환 값을 사용하는 방법에는 위와 같이 사용하는 방법과 then을 사용하는 방법이 있습니다. 그러기 위해선 호출하는 함수의 반환 타입이 Future 클래스에 타입을 명시해줘야 합니다.
플러터 개발 환경 세팅에 앞서 먼저 현재 모바일 시장은 안드로이드와 IOS로 나뉠 수 있고 각 환경의 어플 개발을 위해서 안드로이드는 자바, 코틀린 언어를 통해 개발을 하며 IOS의 경우 Object-C, Swift를 통해 개발을 하고 있습니다. 이렇게 각 운영체제에 맞는 언어로 개발한 것은 네이티브 앱이라고 합니다. 반대로 두 운영체제를 구분하지 않고 구별할 수 있는 방법으로 웹앱, 프로그레시브 웹앱, 하이브리드 앱 등이 등장했습니다.
그러더니 자바스크립트를 사용하는 리액트 네이티브와 다트라는 언어를 사용하는 플러터라는 크로스 플랫폼 프레임워크가 등장하였습니다. 이 중 우리는 플러터라는 프레임워크를 공부해볼 예정입니다.
환경 세팅에 앞서 저의 PC 환경은 Windows 10, Dell Notebook 16GB Ram입니다. 윈도우 환경에 맞춰 개발 및 포스팅이 진행되니 이점 참고 부탁드립니다.