BlogNot. QT: vytvoření upravitelného stromu řádků s libovolným počtem sloupců pro prvky.
QT: Vytvoření upravitelného stromu řádků s libovolným počtem sloupců na prvek
Na rozdíl od tohoto příkladu nebudeme pracovat s widgetem Item-Based Tree View „element-by-element“, ale vše uděláme podle „MVC kánonů“ s využitím widgetu Model-Based Tree Widget. To nám umožní oddělit logické модель data z jejich externí reprezentace (druh). Nevynalezl jsem kolo znovu, ale založil jsem to na těchto příkladech z dokumentace QT5: jednoduchý strom, upravitelný strom.
Vytvoříme widget QTreeModel na základě šablony QWidget.
Data o uzlech stromu budeme ukládat do běžného textového souboru, který propojíme se zdroji projektu.
- kliknutím pravým tlačítkem myši na kořenovou složku projektu v okně Projekty vyberte Přidat nový – QT – QT Resource File, zadejte název simpletreemodel.qrc a přidejte soubor do projektu;
- v editoru zdrojů přidejte kořenový prefix » / «:

Přidejte prefix a poté soubor zdrojů v QT Creatoru
Poté přidejte do zdrojů soubor s názvem default.txt s následujícím obsahem:
Uzel 1. popis uzlu 1 Uzel 1-1. popis uzlu 1-1 Uzel 1-2. popis uzlu 1-2 Uzel 2. popis uzlu 2 Uzel 2-1. popis uzlu 2-1 Uzel 2-1-1. popis uzlu 2-1-1 Uzel 2-1-2. popis uzlu 2-1-2 Uzel 3. popis uzlu 3
Vnoření uzlů stromu je zde znázorněno odsazením bílých znaků vlevo a přechod do nového sloupce je znázorněn symboly . Kódování souboru je Unicode (UTF-8). Samozřejmě následně v kódu zajistíme parsování tohoto formátu souboru.
Aby aplikace mohla použít data zdrojů, stačí je inicializovat pomocí dříve zadaného názvu:
Q_INIT_RESOURCE(jednoduchý stromový model);
a poté přistupte k požadovanému zdroji pomocí jeho předpony a názvu souboru:
":/výchozí.txt"
Zdroje mohou být souborová data libovolného typu.
Náš strom bude seznamem řádků, z nichž některé mohou být podřízeny řádkům umístěným výše v textu. Data každého řádku mohou obsahovat několik sloupců. Pro modelování samostatného prvku takové datové struktury vyvineme a do projektu přidáme třídu TreeItem:
Soubor treeitem.h
#ifndef TREEITEM_H #define TREEITEM_H #include #include #include class TreeItem < public: explicit TreeItem (const QVector&data, TreeItem *parentItem = 0); //Konstruktor uzlu stromu ~TreeItem(); //. a destruktor void appendChild(TreeItem *child); //Přidání podřízeného uzlu TreeItem *child(int row); //Vrátí podřízený prvek int childCount() const; //Počet podřízených položek int columnCount() const; //Vrátí počet sloupců v položce QVariant data(int column) const; //Vrátí data zadaného sloupce int childNumber() const; //Vrátí číslo řádku položky TreeItem *parentItem(); //Vrátí nadřazený prvek bool insertChildren(int position, int count, int columns); //Vložení podřízených položek (řádků) bool insertColumns(int position, int columns); //Vložení sloupců bool removeChildren(int position, int count); //Odstranění podřízených položek bool removeColumns(int position, int columns); //Odstranění sloupců bool setData(int column, const QVariant &value); //Nastavení dat private: //Interní reprezentace dat: QList m_childItems; //Seznam podřízených položek QVector m_itemData; //Seznam dat aktuálního uzlu TreeItem *m_parentItem; //Odkaz na nadřazený uzel >; #endif // TREEITEM_H
Soubor treeitem.cpp
#include "treeitem.h" TreeItem::TreeItem (const QVector &data, TreeItem *parent) < //Konstruktoru uzlu musí být předána data a odkaz na rodiče m_parentItem = parent; m_itemData = data; >TreeItem::~TreeItem() < qDeleteAll(m_childItems); >/* Metody třídy v podstatě slouží jako rozhraní k odpovídajícím metodám standardní třídy QVector: */ void TreeItem::appendChild(TreeItem *item) < m_childItems.append(item); //Přidání uzlu do seznamu potomků >TreeItem *TreeItem::child (int row) < return m_childItems.value(row); //Podle čísla řádku vyberte požadovaný potomek ze seznamu >int TreeItem::childCount() const < return m_childItems.count(); //Počet potomků uzlu = délka seznamu potomků >int TreeItem::columnCount() const < return m_itemData.count(); //Počet sloupců v uzlu = délka seznamu dat uzlu >QVariant TreeItem::data (int column) const < return m_itemData.value(column); //Získání dat z požadovaného sloupce >TreeItem *TreeItem::parentItem() < return m_parentItem; //Vrátí odkaz na rodiče >int TreeItem::childNumber() const < //Pokud existuje rodič - najde jeho číslo v seznamu jeho potomků if (m_parentItem) return m_parentItem->m_childItems.indexOf(const_cast(this)); return 0; //Jinak vrátí 0 > /* Další 4 metody jednoduše spravují kontejnery m_childItems a m_itemData pro ukládání dat */ bool TreeItem::insertChildren(int position, int count, int columns) < if (position < 0 || position >m_childItems.size()) return false; for (int row = 0; row < count; ++row) < QVectordata(columns); TreeItem *item = new TreeItem(data, this); m_childItems.insert(position, item); >return true; > bool TreeItem::insertColumns(int position, int columns) < if (position < 0 || position >m_itemData.size()) return false; for (int column = 0; column < columns; ++column) m_itemData.insert(position, QVariant()); foreach (TreeItem *child, m_childItems) child->insertColumns(position, columns); return true; > bool TreeItem::removeChildren(int pozice, int počet) < if (pozice < 0 || pozice + počet >m_childItems.size()) return false; for (int řádek = 0; řádek < počet; ++řádek) delete m_childItems.takeAt(pozice); return true; >bool TreeItem::removeColumns(int pozice, int sloupce) < if (pozice < 0 || pozice + sloupce >m_itemData.size()) return false; for (int sloupec = 0; sloupec < sloupce; ++sloupec) m_itemData.removeAt(pozice); foreach (TreeItem *child, m_childItems) child->removeColumns(pozice, sloupce); return true; > //A tato metoda vloží hodnotu value do sloupce položky: bool TreeItem::setData(int sloupec, const QVariant &hodnota) < if (sloupec < 0 || sloupec >= m_itemData.size()) return false; m_itemData[sloupec] = hodnota; vrátit true; >
Za model (konkrétně za poskytování indexů modelu) bude zodpovědná třída TreeModel. Měla by být potomkem třídy QAbstractItemModel, která obsahuje prototypy všech metod potřebných pro práci s modelem datových položek.
Soubor treemodel.h
#ifndef TREEMODEL_H #define TREEMODEL_H #include #include #include "treeitem.h" class TreeModel : public QAbstractItemModel < Q_OBJECT public: TreeModel(const QStringList &headers, const QString &data, QObject *parent = 0); ~TreeModel(); /* Objasnění hlaviček metod pomocí správných klíčových slov C++: const - funkce nemění objekt, pro který je volána override - funkce přepíše virtuální metodu základní třídy */ QVariant data(const QModelIndex &index, int role) const override; //získání dat z indexu modelu index s rolí role Qt::ItemFlags flags(const QModelIndex &index) const override; //získání příznaků výběru QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override; //získání dat záhlaví QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override; //získání indexu modelu podle řádku a sloupce QModelIndex parent(const QModelIndex &index) const override; //získání indexu modelu nadřazeného objektu int rowCount(const QModelIndex &parent = QModelIndex()) const override; int columnCount(const QModelIndex &parent = QModelIndex()) const override; //získání počtu řádků a sloupců pro položku s daným indexem modelu bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override; //nastavení dat uzlu s indexem na hodnotu bool setHeaderData(int section, Qt::Orientation orientation, const QVariant &value, int role = Qt::EditRole) override; //nastavení dat záhlaví sloupce bool insertColumns(int position, int columns, const QModelIndex &parent = QModelIndex()) override; bool removeColumns(int position, int columns, const QModelIndex &parent = QModelIndex()) override; bool insertRows(int position, int rows, const QModelIndex &parent = QModelIndex()) override; bool removeRows(int position, int rows, const QModelIndex &parent = QModelIndex()) override; //vkládání a odebírání sloupců a řádků private: void setupModelData(const QStringList &lines, TreeItem *parent); //interní metoda pro nastavení dat modelu TreeItem *getItem(const QModelIndex &index) const; //interní metoda pro získání položky TreeItem *rootItem; //odkaz na kořenový uzel >; #endif // TREEMODEL_H
Soubor treemodel.cpp
#include "treeitem.h" #include "treemodel.h" TreeModel::TreeModel(const QStringList &headers, const QString &data, QObject *parent) : QAbstractItemModel(parent) < QVector rootData; rootData TreeModel::~TreeModel() < delete rootItem; >int TreeModel::columnCount(const QModelIndex &parent) const < return rootItem->columnCount(); > QVariant TreeModel::data (const QModelIndex &index, int role) const < if (!index.isValid()) return QVariant(); if (role != Qt::DisplayRole && role != Qt::EditRole) return QVariant(); TreeItem *item = getItem(index); return item->data(index.column()); > TreeItem *TreeModel::getItem(const QModelIndex &index) const < if (index.isValid()) < TreeItem *item = static_cast(index.internalPointer()); if (item) return item; >return rootItem; > Qt::ItemFlags TreeModel::flags(const QModelIndex &index) const < if (!index.isValid()) return 0; return Qt::ItemIsEditable | QAbstractItemModel::flags(index); >QVariant TreeModel::headerData(int section, Qt::Orientation orientation, int role) const < if (orientation == Qt::Horizontal && role == Qt::DisplayRole) return rootItem->data(section); return QVariant(); > QModelIndex TreeModel::index(int řádek, int sloupec, const QModelIndex &parent) const < if (parent.isValid() && parent.column() != 0) return QModelIndex(); TreeItem *parentItem = getItem(parent); TreeItem *childItem = parentItem->child(řádek); if (childItem) return createIndex(řádek, sloupec, childItem); else return QModelIndex(); > QModelIndex TreeModel::parent(const QModelIndex &index) const < if (!index.isValid()) return QModelIndex(); TreeItem *childItem = getItem(index); TreeItem *parentItem = childItem->parentItem(); if (parentItem == rootItem) return QModelIndex(); return createIndex(parentItem->childNumber(), 0, parentItem); > int TreeModel::rowCount(const QModelIndex &parent) const < TreeItem *parentItem = getItem(parent); return parentItem->childCount(); > void TreeModel::setupModelData(const QStringList &lines, TreeItem *parent) < QListparents; QList indentations; parents //Ořízne úvodní mezery QString lineData = lines[number].mid(position).trimmed(); if (!lineData.isEmpty()) < //Přečte zbytek řádku, pokud existuje QStringList columnStrings = lineData.split(".
Hlavní widget bude poskytovat sloty pro akce prováděné stisknutím tlačítek a implementuje aktualizaci jejich stavu. Rozhraní aplikace je implementováno ve vestavěném návrháři formulářů, takto vypadá:

Rozhraní QT aplikace pro úpravu stromu řetězců
Soubor widget.h
#ifndef WIDGET_H #define WIDGET_H #include #include #include #include namespace Ui < class Widget; >class Widget : public QWidget < Q_OBJECT Ui::Widget *ui; public: Widget(QWidget *parent = 0); void updateActions(); //slot pro aktualizaci stavu tlačítek private slots: //sloty pro akce prováděné tlačítky void insertChild(); bool insertColumn(); void insertRow(); bool removeColumn(); void removeRow(); public slots: //pro implementaci signálu selectionChanged v QTreeView::selectionModel void updateActions(const QItemSelection &,const QItemSelection &); >; #endif // WIDGET_H
Soubor widget.cpp
#include "widget.h" #include "treemodel.h" #include "ui_widget.h" Widget::Widget(QWidget *parent) : QWidget(parent), ui(new Ui::Widget) < ui->setupUi(this); //Инициализируем ресурсы: Q_INIT_RESOURCE(simpletreemodel); //Получаем предустановленное "дерево" в file: QFile file(":/default.txt"); file.open(QIODevice::ReadOnly); //Создаем заголовки столбцов: QStringList headers; headers treeView->setModel(model); for (int column = 0; column < model->columnCount(); ++column) ui->treeView->resizeColumnToContents(column); //Осталось соединить сигналы со слотами: connect(ui->treeView->selectionModel(),SIGNAL(selectionChanged(const QItemSelection&,const QItemSelection&)), this, SLOT(updateActions(const QItemSelection&,const QItemSelection&))); connect(ui->insertRowAction,SIGNAL(clicked()),this,SLOT(insertRow())); connect(ui->insertColumnAction,SIGNAL(clicked()),this,SLOT(insertColumn())); connect(ui->removeRowAction,SIGNAL(clicked()),this,SLOT(removeRow())); connect(ui->removeColumnAction,SIGNAL(clicked()),this,SLOT(removeColumn())); connect(ui->insertChildAction,SIGNAL(clicked()),this,SLOT(insertChild())); //и обновить состояние кнопок: updateActions(); > void Widget::insertChild() < //Получаем модельный индекс и модель элемента: QModelIndex index = ui->treeView->selectionModel()->currentIndex(); QAbstractItemModel *model = ui->treeView->model(); //Вставляем данные: if (model->columnCount(index) == 0) < if (!model->insertColumn(0, index)) return; > if (!model->insertRow(0, index)) return; //Инициализируем их: for (int column = 0; column < model->columnCount(index); ++column) < QModelIndex child = model->index(0, column, index); model->setData(child, QVariant("Данные"), Qt::EditRole); if (!model->headerData(column, Qt::Horizontal).isValid()) model->setHeaderData(column, Qt::Horizontal, QVariant("Столбец"), Qt::EditRole); > //Выбираем вставленный узел: ui->treeView->selectionModel()->setCurrentIndex(model->index(0, 0, index), QItemSelectionModel::ClearAndSelect); //Меняем состояние кнопок: updateActions(); > bool Widget::insertColumn() < QAbstractItemModel *model = ui->treeView->model(); int column = ui->treeView->selectionModel()->currentIndex().column(); bool changed = model->insertColumn(column + 1); if (changed) model->setHeaderData(column + 1, Qt::Horizontal, QVariant("Столбец"), Qt::EditRole); updateActions(); return changed; > void Widget::insertRow() < QModelIndex index = ui->treeView->selectionModel()->currentIndex(); QAbstractItemModel *model = ui->treeView->model(); if (!model->insertRow(index.row()+1, index.parent())) return; updateActions(); for (int column = 0; column < model->columnCount(index.parent()); ++column) < QModelIndex child = model->index(index.row()+1, column, index.parent()); model->setData(child, QVariant("Данные"), Qt::EditRole); > > bool Widget::removeColumn() < QAbstractItemModel *model = ui->treeView->model(); int column = ui->treeView->selectionModel()->currentIndex().column(); bool changed = model->removeColumn(column); //Удалить столбец для каждого потомка if (changed) updateActions(); return changed; > void Widget::removeRow() < QModelIndex index = ui->treeView->selectionModel()->currentIndex(); QAbstractItemModel *model = ui->treeView->model(); if (model->removeRow(index.row(), index.parent())) updateActions(); > void Widget::updateActions(const QItemSelection &selected,const QItemSelection &deselected) < updateActions(); >void Widget::updateActions() < //Обновим состояние кнопок: bool hasSelection = !ui->treeView->selectionModel()->selection().isEmpty(); ui->removeRowAction->setEnabled(hasSelection); ui->removeColumnAction->setEnabled(hasSelection); bool hasCurrent = ui->treeView->selectionModel()->currentIndex().isValid(); ui->insertRowAction->setEnabled(hasCurrent); ui->insertColumnAction->setEnabled(hasCurrent); //Покажем информацию в заголовке окна: if (hasCurrent) < ui->treeView->closePersistentEditor(ui->treeView->selectionModel()->currentIndex()); int row = ui->treeView->selectionModel()->currentIndex().row(); int column = ui->treeView->selectionModel()->currentIndex().column(); if (ui->treeView->selectionModel()->currentIndex().parent().isValid()) this->setWindowTitle(tr("(row,col)=(%1,%2)").arg(row).arg(column)); else this->setWindowTitle(tr("(row,col)=(%1,%2) ВЕРХ").arg(row).arg(column)); > >
Hlavní soubor main.cpp, stejně jako samotný soubor projektu, jsou kompletně šablonové, nebudu je uvádět v textu. Zde je pohled na aplikaci v provozu a projekt v archivu.

Pohled na okno widgetu QTreeModel
02.05.2017, 15:44 [19521 zhlédnutí]
Honba za dokonalým zvukem často končí u přehlídky drahých reproduktorů, ale existuje jeden důležitý prvek, který mnozí ignorují – skříň reproduktoru. Koneckonců hraje klíčovou roli v tom, jak bude hudba znít, ať už se jedná o hluboké basy nebo živý zpěv. V tomto článku si řekneme, jak materiály – od MDF po masivní dřevo – ovlivňují zvuk, který z nich se lépe hodí pro různé žánry a jak vybrat ty správné reproduktory, abyste dosáhli toho velmi „živého“ zvuku.

Honba za „špičkovým zvukem“ pro mnohé končí u vitríny s drahými výškovými a basovými reproduktory. Všichni diskutují o frekvencích, výhybkách, zesilovačích, ale často zcela zapomínají na jeden nepatrný bod – skříň. Ano, tu pravou skříň, ve které se děje všechna magie. A právě zde začíná ta pravá alchymie. Protože kupodivu právě na ní do značné míry závisí, zda vás poslech nadchne, nebo zda budete otáčet knoflíkem hlasitosti a hledat „toho pravého“.

Tělo není jen obal. Je součástí zvukového nástroje. Představte si kytaru bez mechaniky. Struny zvoní, ale hlasitost je nulová. A tak i v akustice – bez správného “dřevěného těla” zní všechno buď suše, nebo jako z pytle. A tady přichází na řadu materiál. Protože dřevo není jen krásné. Opravdu zní. A různými způsoby.
Ne všechny kusy dřeva jsou si rovny
V dnešní době se většina reproduktorů vyrábí z MDF – lisovaného dřevěného prachu namočeného v lepidle. Nezní to sice moc poeticky, ale je to stabilní a předvídatelné. Tento materiál „nechodí“ od vlhkosti, nepraská a snadno se zpracovává. Proto je z něj vyrobeno 90 % moderních akustických systémů.
Ale MDF je jako těstoviny bez soli. Neutrální. Nepřináší nic „svého“. Někdy je to plus: nic nebarví, nezvoní, nerezonuje. Pokud ale chcete „živý“ zvuk, s tělem a vzduchem, je lepší se poohlédnout po překližce, masivním dřevě nebo alespoň dobře slepené vícevrstvé konstrukci.
Překližka zní jinak. Je elastická, jinak vibruje, dodává basům lehký „odskok“. Zvlášť pokud je tělo promyšleně tvarově promyšlené. A masivní dřevo je už o umění. Používá se zřídka kvůli ceně a nestabilitě, ale pokud na něj narazíte, držte se ho oběma rukama. Může to být naprosto jedinečný zvuk, zejména ve středním rozsahu.
Jak materiál ovlivňuje zvuk?
Pojďme se blíže podívat na to, co se přesně stane, když různé materiály „ruší“ zvukový obraz:
Basy: Masivní dřevěná nebo kvalitní překližková skříň pomáhá „snést náraz“, aniž by způsobovala dunění. Špatné dřevo nebo plast naopak mohou vytvářet nežádoucí rezonance, jako by si reproduktor mumlal sám pro sebe.
Středy: Tady se děje ta magie. Přírodní dřevo dokáže trochu „zabarvit“ vokály, ne špatným způsobem, ale jako by jim dodávalo lidské teplo. To je obzvláště patrné u akustických nástrojů.
Vysoké frekvence: méně citlivé na kabinet, ale také zachycují odrazy uvnitř, zejména pokud je kabinet prázdný nebo špatně tlumený.
Je důležité si uvědomit, že pouzdro není jen „design“. Funguje jako součást reproduktorového systému. A zvuk, který slyšíte, je součtem všeho: reproduktoru, filtru a pouzdra.
Plast, sklo, beton – co dalšího jste vyzkoušeli?
Někteří výrobci rádi experimentují. Existují reproduktory vyrobené ze skelných vláken, akrylu, betonu a dokonce i uhlíku. Proč? Aby se eliminovaly vibrace nebo aby se vytvořil efekt „wow!“. Často to ale produkuje zvuk se „sterilním“ charakterem nebo prostě přehnanou suchostí. Někteří lidé to mají rádi, zejména v elektronice a technu – je důležité, aby každý takt byl dokonale vyřezaný.
Ale je tu jedna nuance. Zvuk v takových systémech může být až příliš „chytrý“. Jako ideální partner: všechno je správné, krásné, ale studené. Proto se mnoho audiofilů stále vrací ke dřevu. Není dokonalé. Není rovnoměrné. Ale je živé.
Jak si vybrat materiál pro vaše uši
Řekněme, že si reproduktory nebudete stavět sami, ale chcete vědět, co kupujete. Pak věnujte pozornost označení. Výrobci často píší „tělo – MDF, povrchová úprava – ořechová dýha“. Dýha je tenká vrstva pravého dřeva nalepená navrch. Zní dobře, vypadá draze, ale na zvuku nehraje téměř žádnou roli.
Pokud se tam píše „masivní dřevo“ – to je vážné. Takových modelů je málo, jsou znatelně dražší, ale dostanete nejen reproduktor, ale téměř hudební nástroj. Takové věci je třeba poslouchat ušima, a ne podle popisu na webových stránkách. Mohou být vrtošivé, vyžadují správné umístění, ale znějí tak, že je nebudete chtít vypnout.
Než se vydáte na nákupy, mějte na paměti několik tipů:
Nenechte se zmást vzhledem. Lesklý povrch nemusí nutně znamenat dobrý zvuk.
Pokud je to možné, poslouchejte živě. Nahrávky na YouTube nezachytí „fyzičnost“ zvuku.
Porovnejte pouzdro hmatem. Hustota, tloušťka stěny, vnitřní polstrování – to vše vypovídá hodně.
Vnitřek je také důležitý
Řekněme, že jste našli reproduktory s dobrým dřevem. Všechno je skvělé, ale uvnitř je prázdnota a pár hřebíků. Zvuk bude. nic. Protože uvnitř skříně by měly být speciální podložky pro tlumení stojatých vln. A také tlumicí materiály, které absorbují odrazy. Pokud nic z toho není, i masivní skříň bude znít jako buben.

Některé modely používají „labyrintové“ konstrukce – vzduch v nich prochází po zakřivené dráze, což dává hustší a hlubší basy. To vše lze zjistit buď poslechem, nebo ponořením se do technického popisu. Ano, je to trochu matoucí, ale pokud chcete nejen „zvuk“, ale „ozvučení“ – stojí to za to.
HDMI, Bluetooth, RCA… Jak se orientovat ve světě audio konektorů?
Ve světě audio zařízení existuje jeden nenápadný hrdina – konektor. Ano, ten samý kabel, který jste zapojili „kam se hodí“. Ten může určit, zda hudba zní jako živý koncert nebo jako někdo zapnul rádio ve sklepě. V tomto článku si snadno a s humorem vysvětlíme rozdíly mezi HDMI, RCA, Bluetooth, optikou, jackem a dalšími záludnými věcmi. Poradíme, co si vybrat pro filmy, hudbu, sluchátka a domácí systém, aby vše znělo nejen hlasitě, ale skutečně lahodně.
Jak se audio technologie přizpůsobuje starším a sluchově postiženým uživatelům
S věkem se nejen mění zrak a chůze – ztrácí se i jasnost zvuků. Psí štěkot se zdá být vzdálený a konverzace v hlučném obchodě vypadá, jako by všichni mluvili pod vodou. Není to rozmar, ale ztráta sluchu související s věkem, s níž se potýkají miliony lidí. Ale dobrá zpráva: moderní technologie opět zpřístupňují zvuk. V novém článku si povíme, jak se ze sluchadel staly chytré gadgety, jak sluchátka zesilují řeč, proč chytré telefony potřebují titulky a proč i televize dokáže mluvit „jako člověk“.
Sluchátka a zdraví: Jak se vyhnout ztrátě sluchu při každodenním používání
Také zvyšujete hlasitost, abyste přehlušili hluk metra nebo chaos ve vaší hlavě? Buďte opatrní – vaše uši takovou párty nemusí zvládnout. Tento článek není hororový příběh, ale upřímný a užitečný průvodce tím, jak hlasitost, sluchátka a návyky ovlivňují sluch. Zjistíme, které typy sluchátek jsou bezpečnější, jak pochopit, že váš sluch již začal trpět, a jaká jednoduchá opatření pomohou jej zachovat na dlouhou dobu. Věda, rady a trocha sarkasmu – vše proto, abyste svět slyšeli jasně, a ne jako přes vatovou stěnu.
Deska není jen zvuk, ale rituál: odhalení milovníka hudby
Ve světě, kde všichni už dávno přešli na streamování, zůstává vinyl výjimečný. Proč? Protože nejen hraje hudbu, ale vytváří atmosféru. Je to teplo, hlasitost a „živost“, které digitálnímu zvuku chybí. V tomto článku si povíme, jak se vinyl stává skutečným rituálem: od výběru desky až po cvaknutí jehly. Vysvětlíme, proč vinyl není jen trend, ale návrat k opravdové, hmatatelné hudbě. Staňte se součástí tohoto světa, kde je každý disk celým příběhem.